• 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
    ",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
    ",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
    ",sum - maxflow);
    111     }
    112     return 0;
    113 }
    View Code
  • 相关阅读:
    Extjs 中combobox下拉框初始化赋值
    关于继承的理解
    近来很郁闷
    Java String 常量池理解
    关于时间复杂度的讲解
    List、Set和数组之间的转换(转载)
    提升自我修养的具体方法有哪些?
    Mapped Statements collection does not contain value fo
    io流导出csv
    反射,System.Type类
  • 原文地址:https://www.cnblogs.com/zhexipinnong/p/3246421.html
Copyright © 2020-2023  润新知