题目要求我们选尽量多的点,同时两两不相邻
可以想到把棋盘按照国际象棋的棋盘样式染色,那同一种颜色的点之间肯定是不相邻的,同时我们也就把图转化为了一个二分图
题目要求也就变成了求这个二分图里的最大点权独立集
最大独立集:包含尽量多顶点的集合,其中任意两点不相邻,所谓的不相邻也就是两点没有连边
最小点覆盖:选取最少的点数,使这些点和所有的边都有关联(把所有的边的覆盖)
最大点权独立集=总权值-最小点权覆盖集
其实不难理解,看看定义就知道了
假设现在已经求出了最小点覆盖,那把这些点去掉,剩下的点肯定是不相邻的,也就是说剩下的点可以构成一个独立集
而我们现在求出的覆盖是最小的,所以自然得到的独立集也就是最大的了
那问题就转化为了求最小点权覆盖集
而二分图的最小点覆盖、最小点权覆盖集都可用网络流求解
构图:
超级源点与左边集合的每一点相连,若是求最小点覆盖,权值为1,若是求最小点权覆盖集,权值为该点的点权
超级汇点与右边集合的每一点相连,权值同上
然后将二分图原有的边加进图中,权值为无穷大
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #define ll long long #define mems(a,b) memset(a,b,sizeof(a)) #define ls pos<<1 #define rs pos<<1|1 using namespace std; const int MAXN = 500; const int MAXE = 40500; const int INF = 99999999; struct node{ int s,e,next,cost,val; node(){} node(int a,int b,int c,int d):s(a),e(b),next(c),val(d){} }edge[MAXE]; int tot,ans,n; int first[MAXN],dep[MAXN],gap[MAXN]; int mat[50][50]; int dx[4]={0,0,-1,1}; int dy[4]={1,-1,0,0}; void init(){ tot=0; mems(first,-1); } void addedge(int u,int v,int w){ //cout<<u<<' '<<v<<' '<<w<<endl; edge[tot]=node(u,v,first[u],w); first[u]=tot++; edge[tot]=node(v,u,first[v],0); first[v]=tot++; } int sap(int src,int des){ memset(dep,0,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=des+1; int top=0,ans=0,u=src,i; int cur[MAXN],s[MAXE]; //s[top++]=src; for(i=0;i<=des;i++) cur[i]=first[i]; while(1){ if(u==des){ int minv=INF,pos; for(i=0;i<top;i++){ if(minv>edge[s[i]].val){ minv=edge[s[i]].val; pos=i; } } for(i=0;i<top;i++){ edge[s[i]].val-=minv; edge[s[i]^1].val+=minv; } ans+=minv; top=pos; u=edge[s[pos]].s; } for(i=cur[u];i!=-1;i=edge[i].next) if(edge[i].val&&dep[u]==dep[edge[i].e]+1) break; if(i!=-1){ cur[u]=i; s[top++]=i; u=edge[i].e; } else{ if(--gap[dep[u]]==0) break; int mindep=des+1; for(i=first[u];i!=-1;i=edge[i].next){ if(!edge[i].val) continue; if(mindep>dep[edge[i].e]){ mindep=dep[edge[i].e]; cur[u]=i; } } dep[u]=mindep+1; gap[dep[u]]++; if(u!=src) u=edge[s[--top]].s; } } return ans; } bool ing(int x,int y){ if(x>=0&&x<n&&y>=0&&y<n) return true; return false; } int main(){ //freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ init(); int tot=0; for(int i=0;i<n;i++) for(int j=0;j<n;j++){ scanf("%d",&mat[i][j]); tot+=mat[i][j]; } int src=0; int des=n*n+1; for(int i=0;i<n;i++) for(int j=0;j<n;j++){ if((i+j)%2==0) addedge(src,i*n+j+1,mat[i][j]); else addedge(i*n+j+1,des,mat[i][j]); } for(int i=0;i<n;i++) for(int j=0;j<n;j++) if((i+j)%2==0) for(int k=0;k<4;k++){ int x=i+dx[k]; int y=j+dy[k]; if(!ing(x,y)) continue; addedge(i*n+j+1,x*n+y+1,INF); } printf("%d ",tot-sap(src,des)); } return 0; }