开关问题解析。
在开关问题学习中学到了。如何处理开关问题。比如POJ 3276中一行决定如何开关。(当区间长度确定)那么就认为第一列只能由第二列改变方向(当他需要改变时)所以就从头往后遍历知道所有都好,最后检查一下是否满足。这个是我之前会的但是我不会的是如何处理着区间。原本是直接把正反改变一次改变以区间这样复杂度就太大了。现在学到一个新的办法。
当判断当前节点node1是否反转的时候,前面某个节点node要发生改变的令f【node】为1。当node+k涉及当前结点node1时那么node1是不是要反转?所以将f【i】(i在i-k+1到i-1中)求和奇数则要反转偶数不反转。这样处理就简单。不限于一行,求当前节点是否反转,只需要将有可能波及他的f相加即可(比如下面)
由于那道题比较简单所以不写POJ 3279简单讲下
先放AC代码
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=20;
int mp[maxn][maxn],anss[maxn][maxn];
int n,m;
int flip[maxn][maxn];
int dx[5]={-1,0,0,0,1};
int dy[5]={0,-1,0,1,0};
int get(int x,int y){
int ans=mp[x][y];
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++){
int nx=x+i,ny=y+j;
if(nx>=0&&nx<n&&ny>=0&&ny<m&&(!i||!j||(!i&&!j)))
ans+=flip[nx][ny];
}
return ans%2;
}
int calc(){
for(int i=0;i<n-1;i++)
for(int j=0;j<m;j++){
if(get(i,j))//heise
flip[i+1][j]=1;
}
for(int i=0;i<m;i++){
if(get(n-1,i))return -1;
}
int cou=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
cou+=flip[i][j];
}
return cou;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&mp[i][j]);
int ans=0x3f3f3f3f;
for(int s=0;s<(1<<m);s++){
memset(flip,0, sizeof(flip));
for(int j=0;j<m;j++)flip[0][m-j-1]=(s>>j)&1;
int num=calc();
if(num>=0&&ans>num){
ans=num;
memcpy(anss,flip, sizeof(flip));
}
}
if(ans==0x3f3f3f3f)printf("IMPOSSIBLE\n");
else for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
printf("%d%c",anss[i][j],j==m-1?'\n':' ');
}
换个方式找搜索
int ans=mp[x][y];
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++){
int nx=x+i,ny=y+j;
if(nx>=0&&nx<n&&ny>=0&&ny<m&&(!i||!j||(!i&&!j)))
ans+=flip[nx][ny];
}
return ans%2;
原版代码
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=20;
int mp[maxn][maxn],anss[maxn][maxn];
int n,m;
int flip[maxn][maxn];
int dx[5]={-1,0,0,0,1};
int dy[5]={0,-1,0,1,0};
int get(int x,int y){
int ans=mp[x][y];
for(int d=0;d<5;d++){
int x2=x+dx[d],y2=y+dy[d];
if(0<=x2&&x2<n&&0<=y2&&y2<m)
ans+=flip[x2][y2];
}
return ans%2;
}
int calc(){
for(int i=1;i<n;i++)
for(int j=0;j<m;j++){
if(get(i-1,j)!=0)//heise
flip[i][j]=1;
}
for(int i=0;i<m;i++){
if(get(n-1,i))return -1;
}
int res=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
res+=flip[i][j];
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&mp[i][j]);
int ans=0x3f3f3f3f;
for(int s=0;s<(1<<m);s++){
memset(flip,0, sizeof(flip));
for(int j=0;j<m;j++)
flip[0][m-j-1]=(s>>j)&1;
int num=calc();
if(num>=0&&ans>num){
ans=num;
memcpy(anss,flip, sizeof(flip));
}
}
if(ans==0x3f3f3f3f)printf("IMPOSSIBLE\n");
else for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
printf("%d%c",anss[i][j],j==m-1?'\n':' ');
}
错误代码(各位聚聚看看为什么呀)
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=20;
int mp[maxn][maxn],anss[maxn][maxn];
int n,m;
int flip[maxn][maxn];
int dx[5]={-1,0,0,0,1};
int dy[5]={0,-1,0,1,0};
int get(int x,int y){
int ans=mp[x][y];
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++){
int nx=x+i,ny=y+j;
if(nx>=0&&nx<n&&ny>=0&&ny<m&&(!i||!j||(!i&&!j)))
ans+=flip[nx][ny];
}
return ans%2;
}
int calc(){
int cou=0;
for(int i=0;i<n-1;i++)
for(int j=0;j<m;j++){
if(get(i,j))//heise
{flip[i+1][j]=1;cou++;}
}
for(int i=0;i<m;i++){
if(get(n-1,i))return -1;
}
return cou;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&mp[i][j]);
int ans=0x3f3f3f3f;
for(int s=0;s<(1<<m);s++){
memset(flip,0, sizeof(flip));
int num=0;
for(int j=0;j<m;j++)
{flip[0][m-j-1]=(s>>j)&1;
if(flip[0][m-j-1])num++;}
num+=calc();
if(num>=0&&ans>num){
ans=num;
memcpy(anss,flip, sizeof(flip));
}
}
if(ans==0x3f3f3f3f)printf("IMPOSSIBLE\n");
else for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
printf("%d%c",anss[i][j],j==m-1?'\n':' ');
}