题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=307
题目大意:
现在有一个网格,每个格子上填了1或0。
先给出每相邻四个格子的和。
求可行方案
算法:
其实我们不难看出,
整个网格的状态是由第一行和第一列决定的。
我们不妨枚举(0,0)的状态,
然后再根据给出的和对于所有其它第一行和第一列的格子做限制。
然后通过2-SAT得出第一行和第一列的合法状态。
最后简单递推即可。
代码如下:
#include<cstdio> #include<cstring> #include<stack> #include<algorithm> #include<vector> #include<climits> using namespace std; const int MAXN=1500; const int MAXM=310; int blkn; int low[MAXN],dep[MAXN],blk[MAXN],fst[MAXN],hash[MAXN]; int a[MAXM][MAXM],b[MAXM][MAXM],c[MAXM][MAXM]; vector<int>map[MAXN]; stack<int>stk; void tarjan(int p,int u) { if(dep[u]==-1) { int tmp=low[u]=dep[u]=(p==-1)?0:dep[p]+1; stk.push(u); for(int i=0; i<map[u].size(); i++) { int v=map[u][i]; tarjan(u,v); tmp=min(tmp,low[v]); } low[u]=tmp; if(low[u]==dep[u]) { fst[blkn]=u; while(1) { int v=stk.top(); stk.pop(); blk[v]=blkn; low[v]=INT_MAX; if(u==v)break; } blkn++; } } } int main() { int n,m; scanf("%d%d",&n,&m); char s[500]; getchar(); for(int i=1; i<n; i++) { gets(s); for(int j=1; j<m; j++) c[i][j]=s[j-1]-'0'; } for(int state=0; state<2; state++) { memset(dep,-1,sizeof(dep)); blkn=0; for(int i=0; i<2*(n+m-2); i++) { map[i].clear(); } memset(b,0,sizeof(b)); a[0][0]=b[0][0]=state; for(int i=1; i<n; i++) for(int j=1; j<m; j++) { b[i][j]=c[i][j]-b[i-1][j]-b[i][j-1]-b[i-1][j-1]; } for(int i=1; i<n; i++) for(int j=1; j<m; j++) for(int x=0; x<2; x++) for(int y=0; y<2; y++) { int tmp=b[i][j]; if(i&1) tmp-=x; else tmp+=x; if(j&1) tmp-=y; else tmp+=y; if(tmp<0||tmp>1) { int lx=((i-1)<<1)+y; int ly=((n+j-2)<<1)+x; map[lx].push_back(ly^1); map[ly].push_back(lx^1); } } for(int i=0; i<2*(n+m-2); i++) { tarjan(-1,i); } { int i; for(i=0; i<2*(n+m-2); i+=2) { if(blk[i]==blk[i|1])break; } if(i<2*(n+m-2)) { continue; } } memset(hash,-1,sizeof(hash)); for(int i=0; i<blkn; i++) if(hash[i]==-1) { hash[i]=1; hash[blk[fst[i]^1]]=0; } for(int i=1; i<n; i++) a[i][0]=hash[blk[((i-1)<<1)|1]]; for(int j=1; j<m; j++) a[0][j]=hash[blk[((n+j-2)<<1)|1]]; for(int i=1; i<n; i++) for(int j=1; j<m; j++) { a[i][j]=c[i][j]-a[i-1][j-1]-a[i-1][j]-a[i][j-1]; } for(int i=0; i<n; i++) { if(i)puts(""); for(int j=0; j<m; j++) { printf("%d",a[i][j]); } } return 0; } puts("CORRUPT"); return 0; }