题意:一个n*m的棋盘,最大是5*5的,最多25个格子,然后在格子上涂色,告诉你有a种颜色,每种颜色涂xi个格子,问有没有一种涂法,使得相邻的格子颜色都不一样,有临边才算相邻。
思路:一道考验智商的题目,首先想到的肯定是爆搜了,但是需要剪枝,但是不知道如何下手。首先可以确定的是,只要有一个x>(n*m+1)/2,直接就挂掉了,输出NO,然后想着想着就觉得这个东西应该能贪心解决。首先把不同颜色的多少排个序,把最多的那个颜色拿出来,斜着往格子里放,斜着空一行放一行,放完最多的一种颜色就放最少的颜色(其实放完最多的接着放最多的也无妨吧,为了保险,就先这样了。。。),然后依次放就好了。贪心的解决掉。注意这里有个小技巧,可以用一个截距b来控制一个斜行的参数,代码简单一些。
感想:这是一道北京区域赛的银牌题,现场只有39个AC的队伍,但是我跟队友在私下做,半个小时就A了,这说明题目真的不可怕,只要现场赛中沉着冷静,一定能拿出好名次的
4 1 5 2 4 1 3 3 4 1 2 2 4 2 3 3 2 2 2 3 2 3 2 2 2
Case #1: NO Case #2: YES 4 3 4 2 1 2 4 3 4 Case #3: YES 1 2 3 2 3 1 Case #4: YES 1 2 2 3 3 1
#include <iostream> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string> #include <string.h> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <stack> using namespace std; typedef long long LL; const int INF=0x7fffffff; const int MAX_N=10000; struct node{ int num; int c; friend bool operator<(const node &a,const node &b){ return a.num<b.num; } }; int T; node C[30]; int F[10][10]; int n,m,k; int main(){ cin>>T; int t=T; while(T--){ memset(F,0,sizeof(F)); int flag=0; scanf("%d%d%d",&n,&m,&k); for(int i=0;i<k;i++){ scanf("%d",&C[i].num); C[i].c=i+1; if(C[i].num>(n*m+1)/2){ flag=1; } } if(flag==1){ printf("Case #%d:\nNO\n",t-T); continue; } sort(C,C+k); /* cout<<"_______________________"<<endl; for (int i=0;i<k;i++) cout<<C[i].c<<" "<<C[i].num<<endl; cout<<"_______________________"<<endl; */ int curc=k-1; int head,tail,now; head=0;tail=k-1;now=tail; int sum=n*m;int b; if (n%2==1 && m%2==1) b=0;else b=1; while (sum>0){ for (int i=0;i<=b && i<n;i++) { int j=b-i; if (j>=m) continue; sum--; F[i][j]=C[now].c; C[now].num--; if (C[now].num==0) { if (now==tail) {now=head;tail--;} else {now=tail;head++;} } } b+=2; if (b>n+m-2) { if (n%2==1 && m%2==1) b=1;else b=0; } } printf("Case #%d:\nYES\n",t-T); for(int i=0;i<n;i++){ printf("%d",F[i][0]); for(int j=1;j<m;j++){ printf(" %d",F[i][j]); } putchar(10); } } return 0; }