2 2 1 2 2 2 2 1 1 2 2 1 2 7 4 1 1 1
4 9HintAs to the second case in Sample Input, onmylove gan get the highest score when calulating like this: 2 + 7 + 4 - 2 × (2&4) - 2 × (2&7) = 13 - 2 × 0 - 2 × 2 = 9.
【题意】
给出一个n*m的格子,格子里有分数,取出得到相应的分数,若取出后导致相邻的格子都为0分,则应减去2*(score1 & score2),附加了某些格子是必须被选择的。求能得到的最大分数。
【思路】
建图:把i+j为偶数作为左边节点,为奇数作为右边节点,设超级源点和汇点source、sink,source连接左边节点,流量为格子的分数;右边节点连接sink,流量为格子的分数;对于必须选择的格子,只需把流量修改为inf,如左边节点与右边节点相邻,则连边,流量为2*(score1 & score2)。求最小点权覆盖集=最小割=最大流。最后结果等于所有格子分数总和 - 最小点权覆盖集大小。
把图按照横纵坐标和的奇数偶数划分成二分图,建立源点和汇点,源点和奇数相连,权值为其点权值,偶数和汇点相连,权值也为点权值,把图中相邻的点相连,权值为2*(a&b),把必须要选取的点和源点或者汇点相连,权值为inf,表示不会割掉这条边;
程序:
#include"stdio.h" #include"string.h" #define M 100005 #define inf 999999999 int min(int a,int b) { return a<b?a:b; } struct st { int u,v,next,w; }edge[M]; int head[M],work[M],q[M],dis[M],t; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w) { edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].next=head[u]; head[u]=t++; edge[t].u=v; edge[t].v=u; edge[t].w=0; edge[t].next=head[v]; head[v]=t++; } int bfs(int S,int T) { int rear=0; memset(dis,-1,sizeof(dis)); dis[S]=0; q[rear++]=S; for(int i=0;i<rear;i++) { for(int j=head[q[i]];j!=-1;j=edge[j].next) { int v=edge[j].v; if(edge[j].w&&dis[v]==-1) { dis[v]=dis[q[i]]+1; q[rear++]=v; if(v==T) return 1; } } } return 0; } int dfs(int S,int a,int T) { if(S==T) return a; for(int &i=work[S];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]==dis[S]+1) { int tt=dfs(v,min(a,edge[i].w),T); if(tt) { edge[i].w-=tt; edge[i^1].w+=tt; return tt; } } } return 0; } int Dinic(int S,int T) { int ans=0; while(bfs(S,T)) { memcpy(work,head,sizeof(head)); while(int tt=dfs(S,inf,T)) ans+=tt; } return ans; } int main() { int n,m,i,j,k,mp[55][55],use[55][55]; while(scanf("%d%d%d",&n,&m,&k)!=-1) { int sum=0; memset(use,0,sizeof(use)); for(i=0;i<n;i++) { for(j=1;j<=m;j++) { scanf("%d",&mp[i][j]); sum+=mp[i][j]; } } for(i=1;i<=k;i++) { int a,b; scanf("%d%d",&a,&b); a--; use[a][b]=1; } init(); for(i=0;i<n;i++) { for(j=1;j<=m;j++) { if((i+j)&1) { if(use[i][j]) add(0,i*m+j,inf); add(0,i*m+j,mp[i][j]); if(j+1<=m) add(i*m+j,i*m+j+1,2*(mp[i][j]&mp[i][j+1])); if(i+1<n) add(i*m+j,(i+1)*m+j,2*(mp[i][j]&mp[i+1][j])); } else { if(use[i][j]) add(i*m+j,m*n+1,inf); add(i*m+j,m*n+1,mp[i][j]); if(j+1<=m) add(i*m+j+1,i*m+j,2*(mp[i][j]&mp[i][j+1])); if(i+1<n) add((i+1)*m+j,i*m+j,2*(mp[i][j]&mp[i+1][j])); } } } //for(i=0;i<t;i+=2) //printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w); int ans=Dinic(0,m*n+1); printf("%d\n",sum-ans); } }