【题目描述】
这是在阿尔托利亚·潘德拉贡成为英灵前的事情,她正要去拔出石中剑成为亚瑟王,在这之前她要去收集一些宝石。
宝石排列在一个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
【提示】
在此键入。
【来源】
姚金宇的原创题,有修改
solution:
明确两条性质:
1.一个宝石只能在偶数时刻被吃掉
2.最终的结果与起始位置无关
那么我们可以将矩阵像棋盘上一样黑白染色
由于如果一个点被吃,那么它周围的点一定不能被吃
所以将黑点与S(起点)连 v=1的边 将白点与T(终点)连 v=1的边 将黑点周围的4个(或不到4个)白点连 v=INF的边
最后用最大流求最小割即可
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 const int INF=(1<<31)-1; 7 inline int minn(int a,int b){return a<b?a:b;} 8 struct son 9 { 10 int v,next,w,u; 11 }; 12 son a1[500001]; 13 int first[500001],e; 14 15 void addbian(int u,int v,int w) 16 { 17 a1[e].u=u; 18 a1[e].v=v; 19 a1[e].w=w; 20 a1[e].next=first[u]; 21 first[u]=e++; 22 } 23 24 int dui[10000001],he,en; 25 inline void clear(){he=1;en=0;} 26 inline void push(int x){dui[++en]=x;} 27 inline int top(){return dui[he];} 28 inline void pop(){++he;} 29 inline bool empty(){return en>=he?0:1;} 30 31 int n,m,u,o,S,T,sum; 32 int ji[101][101]; 33 int hh[101][101]; 34 35 int dep[20001]; 36 int bfs() 37 { 38 mem(dep,0);clear(); 39 dep[S]=1;push(S); 40 while(!empty()) 41 { 42 int now=top();pop(); 43 //printf("now=%d ",now); 44 for(int i=first[now];i!=-1;i=a1[i].next) 45 { 46 int temp=a1[i].v; 47 //printf("temp=%d ",temp); 48 if(!a1[i].w||dep[temp])continue; 49 dep[temp]=dep[now]+1; 50 push(temp); 51 if(temp==T)return 1; 52 } 53 } 54 return 0; 55 } 56 57 int dfs(int x,int val) 58 { 59 //printf("x=%d ",x); 60 if(x==T)return val; 61 int val2=val,k; 62 for(int i=first[x];i!=-1;i=a1[i].next) 63 { 64 int temp=a1[i].v; 65 //printf("temp=%d ",temp); 66 if(dep[temp]!=dep[x]+1||!a1[i].w||!val2)continue; 67 k=dfs(temp,minn(val2,a1[i].w)); 68 if(!k){dep[temp]=0;continue;} 69 a1[i].w-=k;a1[i^1].w+=k;val2-=k; 70 } 71 return val-val2; 72 } 73 74 int Dinic() 75 { 76 int ans=0; 77 while(bfs()) 78 ans+=dfs(S,INF); 79 return ans; 80 } 81 82 void out11() 83 { 84 printf(" "); 85 /*for(int i=1;i<=n;++i) 86 { 87 for(int j=1;j<=m;++j) 88 printf("%d ",ji[i][j]); 89 printf(" "); 90 }*/ 91 for(int i=S;i<=T;++i) 92 { 93 printf("i=%d ",i); 94 for(int j=first[i];j!=-1;j=a1[j].next) 95 printf("%d ",a1[j].v); 96 printf(" "); 97 } 98 printf(" "); 99 } 100 101 int main(){ 102 //freopen("1.txt","r",stdin); 103 freopen("Excalibur.in","r",stdin); 104 freopen("Excalibur.out","w",stdout); 105 mem(first,-1); 106 scanf("%d%d",&n,&m); 107 S=0;T=n*m+1; 108 for(int i=1;i<=m;++i) 109 ji[1][i]=i&1; 110 for(int i=2;i<=n;++i) 111 { 112 ji[i][1]=ji[i-1][2]; 113 for(int j=2;j<=m;++j) 114 ji[i][j]=ji[i-1][j-1]; 115 } 116 117 for(int i=1;i<=n;++i) 118 for(int j=1;j<=m;++j) 119 hh[i][j]=(i-1)*m+j; 120 121 //out11(); 122 123 for(int i=1;i<=n;++i) 124 for(int j=1;j<=n;++j) 125 { 126 scanf("%d",&u); 127 sum+=u; 128 if(ji[i][j]) 129 { 130 addbian(S,hh[i][j],u); 131 addbian(hh[i][j],S,0); 132 } 133 else 134 { 135 addbian(hh[i][j],T,u); 136 addbian(T,hh[i][j],0); 137 } 138 } 139 140 //out11(); 141 142 for(int i=1;i<=n;++i) 143 for(int j=1;j<=m;++j) 144 if(ji[i][j]) 145 { 146 if(i>1) 147 { 148 addbian(hh[i][j],hh[i-1][j],INF); 149 addbian(hh[i-1][j],hh[i][j],0); 150 } 151 if(i<n) 152 { 153 addbian(hh[i][j],hh[i+1][j],INF); 154 addbian(hh[i+1][j],hh[i][j],0); 155 } 156 if(j>1) 157 { 158 addbian(hh[i][j],hh[i][j-1],INF); 159 addbian(hh[i][j-1],hh[i][j],0); 160 } 161 if(j<m) 162 { 163 addbian(hh[i][j],hh[i][j+1],INF); 164 addbian(hh[i][j+1],hh[i][j],0); 165 } 166 } 167 168 //out11(); 169 170 //cout<<0; 171 printf("%d",sum-Dinic()); 172 //while(1); 173 return 0; 174 }