王者之剑
这是在阿尔托利亚·潘德拉贡成为英灵前的事情,她正要去拔出石中剑成为亚瑟王,在这之前她要去收集一些宝石。
宝石排列在一个n*m的网格中,每个网格中有一块价值为v(i,j)的宝石,阿尔托利亚·潘德拉贡可以选择自己的起点。
开始时刻为0秒。以下操作,每秒按顺序执行
1.在第i秒开始的时候,阿尔托利亚·潘德拉贡在方格(x,y)上,她可以拿走(x,y)中的宝石。
2.在偶数秒,阿尔托利亚·潘德拉贡周围四格的宝石会消失
3.若阿尔托利亚·潘德拉贡第i秒开始时在方格(x,y)上,则在第i+1秒可以立即移动到(x+1,y),(x,y+1),(x-1,y)或(x,y-1)上,也可以停留在(x,y)上。
求阿尔托利亚·潘德拉贡最多可以获得多少价值的宝石
【输入格式】
第一行给出数字N,M代表行列数.N,M均小于等于100,宝石的价值不会超过10000.下面N行M列用于描述数字矩阵
【输出格式】
输出最多可以拿到多少价值宝石
【样例输入】
2 2
1 2
2 1
【样例输出】
4
【题解】
论黑白点染色是怎样一个常用套路……因为每个点和它周围一圈的四个点一定不能同时拿到,而且只有偶数时刻可以取数,所以把不相容的点之间建一条权值极大的边。每个黑点和源点、白点和汇点之间的边权值为这个点的价值。对于白点来说汇点的意义是选、源点是不选,对于黑点正相反,这就是翻转源汇的思想。最小割中割掉的边是被舍弃的边,用刚开始矩阵的总权值减去割的权值即可。注意即使建极大值的边也是正向极大反向为0,否则可能会出现很多不可知的错误。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int sj=105; int n,m,vl[sj][sj],h[sj*sj],e,s,t,sx[sj][sj],jg,dep[sj*sj],ma; bool hb[sj][sj]; struct B { int ne,v,w; }b[sj*sj*10]; void add(int x,int y,int z) { b[e].v=y; b[e].w=z; b[e].ne=h[x]; h[x]=e++; } int bj(int x,int y) { return x<y?x:y; } void init() { scanf("%d%d",&n,&m); memset(h,-1,sizeof(h)); s=0; t=n*m+1; ma=1000010; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&vl[i][j]); if((i&1)==(j&1)) hb[i][j]=1; jg+=vl[i][j]; sx[i][j]=m*(i-1)+j; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(hb[i][j]) { add(s,sx[i][j],vl[i][j]),add(sx[i][j],s,0); if(i-1) add(sx[i][j],sx[i-1][j],ma),add(sx[i-1][j],sx[i][j],0); if(j-1) add(sx[i][j],sx[i][j-1],ma),add(sx[i][j-1],sx[i][j],0); if(i+1<=n) add(sx[i][j],sx[i+1][j],ma),add(sx[i+1][j],sx[i][j],0); if(j+1<=m) add(sx[i][j],sx[i][j+1],ma),add(sx[i][j+1],sx[i][j],0); } if(!hb[i][j]) add(sx[i][j],t,vl[i][j]),add(t,sx[i][j],0); } } queue<int> q; bool bfs(int x) { memset(dep,0,sizeof(dep)); dep[x]=1; while(!q.empty()) q.pop(); q.push(x); while(!q.empty()) { x=q.front(); q.pop(); for(int i=h[x];i!=-1;i=b[i].ne) if(b[i].w&&!dep[b[i].v]) { dep[b[i].v]=dep[x]+1; if(b[i].v==t) return 1; q.push(b[i].v); } } return 0; } int dfs(int x,int f) { int ans=0; if(x==t) return f; for(int i=h[x],d;i!=-1;i=b[i].ne) if(b[i].w&&dep[b[i].v]>dep[x]) { d=dfs(b[i].v,bj(b[i].w,f)); f-=d; ans+=d; b[i].w-=d; b[i^1].w+=d; } if(!ans) dep[x]=-1; return ans; } int main() { //freopen("t.txt","r",stdin); freopen("Excalibur.in","r",stdin); freopen("Excalibur.out","w",stdout); init(); while(bfs(s)) jg-=dfs(s,ma*100); printf("%d",jg); //while(1); return 0; }
南风知我意,吹梦到西洲。