题目链接: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;
}