标签:scan problem == cstring 价值 font get printf 网络流
Solution
可以利用网络流对“斥”的求解
先假设所有点都选,不选某些点可以使选择的方案合法,求出这些不选的点的价值总和的最小值
最小值联想到最小割
根据(横坐标+纵坐标)的奇偶性将图分成两部分
在不能同时选的点间连边(方向偶-奇),由于“割”时不能割掉点之间不能同时选的关系,所以它的流量应为正无穷
再从起点向偶部的每个点连一条流量为这个点的价值的边,从奇部的每个点向终点连一条流量为这个点的价值的边,
表示不选它失去的价值
跑最大流(即最小割)
Code
#include <cstdio> #include <cstdlib> #include <queue> #include <algorithm> #include <cstring> using namespace std; const int N=1e4+10,M=1e5; int head[N],nxt[M],ver[M],edge[M],tot=1; int s,t,n,m,d[N],x,maxflow,flow,sum,inf=1<<30; int id(int x,int y) { return (x-1)*m+y; } void add(int u,int v,int w) { ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,head[u]=tot; ver[++tot]=u,nxt[tot]=head[v],edge[tot]=0,head[v]=tot; } int bfs() { queue <int> q; memset(d,0,sizeof(d)); d[s]=1,q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x],y;i;i=nxt[i]) if(edge[i]>0 && !d[y=ver[i]]) { d[y]=d[x]+1; q.push(y); if(y==t) return 1; } } return 0; } int dinic(int x,int flow) { if(x==t) return flow; int rest=flow; for(int i=head[x],y;i && rest;i=nxt[i]) if(edge[i]>0 && d[y=ver[i]]==d[x]+1) { int k=dinic(y,min(edge[i],rest)); if(!k) d[y]=0; edge[i]-=k,edge[i^1]+=k; rest-=k; } return flow-rest; } int main() { scanf("%d%d",&n,&m); s=0,t=n*m+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&x); sum+=x; if((i+j)%2) { add(id(i,j),t,x); continue; } add(s,id(i,j),x); if(i>1) add(id(i,j),id(i-1,j),inf); if(i<n) add(id(i,j),id(i+1,j),inf); if(j>1) add(id(i,j),id(i,j-1),inf); if(j<m) add(id(i,j),id(i,j+1),inf); } while(bfs()) while(flow=dinic(s,1<<30)) maxflow+=flow; printf("%d\n",sum-maxflow); return 0; }
标签:scan problem == cstring 价值 font get printf 网络流
原文地址:https://www.cnblogs.com/hsez-cyx/p/12407490.html