HDU 3657 Game

作为一个刚入门网络流的弱菜,表示看到这个题,实在建不出图。直接在discuss看的别人怎么建图的。既然看了别人的建图方法,那只能讲讲目前的理解了。

 题意: 给定一个 n * m 大小的矩阵, 矩阵中每个格子都有一个不大于 1000 的正整数, 现在要从矩阵中选出若干个格子, 使得得分最大. 得分等于选取的格子里的数字和. 如果有两个格子相邻, 则得分将减去 2 * (x & y), x 和 y 为相邻两个格子内的数字. 此外, 还有一些格子是必选的.

二分图最小点权覆盖的建图方法:

建立超级源点S和超级汇点T,对于二分图X,Y中的点,从S向X连一条容量为X权值的边,从Y向T连一条容量为Y权值的边,其余边容量无穷大。由S->T做一遍最大流。对于该图中任意一个割,那个割所对应的点就是一个可行解,最小权和为割的容量。

在本题中:建立超级源点S和超级汇点T,对行号i+列号j为奇数的点作为二分图X中的点,为偶数的作为二分图中Y中的点,从S向X连边,从Y向T连边,若该节点必选,则容量为+INF,否则,容量为该带你权值,对于从X到Y中的可以相邻的点(就是在原图中有公共边的格子对应的点),容量设置成2*(x&y)。由S->T做一次最大流,最终答案是所有格子中的点的权值之和sum-Maxflow(S->T)。

看完这个建图方法,我瞬间就冒出很多傻逼的问题。。以下是一些自问自答。。答的不一定对。

1.最大流=最小割,这张图中的最小割对应的就是在原矩阵中损失掉的分数。那么在本题中,就是要使分数流失最小。那如果我让总流量小一点,那不是分数损失的更少吗?对于一条边上分数的损失,要么就损失,要么就不损失,损失的时候就一定达到满流。

2.为什么必选点到源汇点的流量必须是+INF?容量无穷,改变不可能成为最小割的边,也以为着这条边一定上的分数不能损失,也就是必选。那么对其他点,容量有限,就有可能出现在最小割中,从而那条边上的值成为被牺牲掉的分数。

3.X,Y之间的点的流量为什么要设置成2*(x&y)?为了限制损失。如果没有满流,就说明损失这条边上的分数不值得。

4.同上,那为什么在二分图最小点权覆盖问题中,X->Y的边上的容量可以设为+INF?同样把流量看成一种损失。容量设置成INF,意味着不用去权衡这条边上的损失,造成损失的根源不在这条边,而是在从源点S到X中的点的那条边上。

这只是现在的理解。。应该有一些不合理的地方。。说不定我以后回过头来看这篇东西,会觉得好搞笑。。

贴代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 #include <vector>
  6 #include <algorithm>
  7 #define maxn 3000
  8 #define maxm 15000
  9 #define INF 1<<30
 10 using namespace std;
 11 
 12 int n,m,k,S,T,e;
 13 int score[55][55];
 14 bool flag[55][55];
 15 int dx[] = {0,-1,0,1};
 16 int dy[] = {1,0,-1,0};
 17 int first[maxn],v[maxm],w[maxm],next[maxm];
 18 int d[maxn],q[maxn],work[maxn];
 19 
 20 void init(){
 21     memset(first,-1,sizeof(first));
 22     e = 0;
 23 }
 24 
 25 void add_edge(int a,int b,int c){
 26     //printf("addedge %d %d %d\n",a,b,c);
 27     v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++;
 28     v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++;
 29 }
 30 
 31 int bfs(){
 32     int i,j,rear = 0;
 33     memset(d,-1,sizeof(d));
 34     d[S] = 0;q[rear++] = S;
 35     for(int i = 0;i < rear;i++){
 36         for(int j = first[q[i]];j != -1;j = next[j])
 37             if(w[j] && d[v[j]] == -1){
 38                 d[v[j]] = d[q[i]] + 1;
 39                 q[rear++] = v[j];
 40                 if(v[j] == T)   return 1;
 41             }
 42     }
 43     return 0;
 44 }
 45 
 46 int dfs(int cur,int a){
 47     if(cur == T)    return a;
 48     for(int &i = work[cur];i != -1;i = next[i])
 49         if(w[i] && d[v[i]] == d[cur] + 1)
 50             if(int t = dfs(v[i],min(a,w[i]))){
 51                 w[i] -= t;w[i^1] += t;
 52                 return t;
 53             }
 54     return 0;
 55 }
 56 
 57 int dinic(){
 58     int ans = 0,t;
 59     while(bfs()){
 60         memcpy(work,first,sizeof(first));
 61         while(t = dfs(S,INF))   ans += t;
 62     }
 63     return ans;
 64 }
 65 
 66 int ID(int row,int column){
 67     if(row < 1 || row > n)  return 0;
 68     if(column < 1 || column > m) return 0;
 69     return (row-1) * m + column;
 70 }
 71 
 72 int main()
 73 {
 74     while(scanf("%d%d%d",&n,&m,&k) == 3){
 75         init();
 76         int sum = 0;
 77         S = 0,T = n*m+1;
 78         memset(flag,0,sizeof(flag));
 79         for(int i = 1;i <= n;i++){
 80             for(int j = 1;j <= m;j++){
 81                 scanf("%d",&score[i][j]);
 82                 sum += score[i][j];
 83             }
 84         }
 85         for(int i = 0;i < k;i++){
 86             int a,b;
 87             scanf("%d%d",&a,&b);
 88             flag[a][b] = true;
 89         }
 90         for(int i = 1;i <= n;i++){
 91             for(int j = 1;j <= m;j++){
 92                 if((i + j) % 2 == 0){
 93                     if(flag[i][j])  add_edge(S,ID(i,j),INF);
 94                     else            add_edge(S,ID(i,j),score[i][j]);
 95                     for(int k = 0;k < 4;k++){
 96                         int x = i + dx[k];
 97                         int y = j + dy[k];
 98                         if(ID(x,y) != 0){
 99                             //printf("i = %d,j = %d,k = %d,x = %d,y = %d\n",i,j,k,x,y);
100                             add_edge(ID(i,j),ID(x,y),2*(score[i][j]&score[x][y]));
101                         }
102                     }
103                 }else{
104                     if(flag[i][j])  add_edge(ID(i,j),T,INF);
105                     else            add_edge(ID(i,j),T,score[i][j]);
106                 }
107             }
108         }
109         int maxflow = dinic();
110         printf("%d\n",sum - maxflow);
111     }
112     return 0;
113 }
View Code

 

posted @ 2013-08-08 18:32  浙西贫农  阅读(271)  评论(0编辑  收藏  举报