zoukankan      html  css  js  c++  java
  • [codevs 1227] 方格取数 2

    题目描述 Description
     给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大
    输入描述 Input Description

    第一行两个数n,k(1<=n<=50, 0<=k<=10)

    接下来n行,每行n个数,分别表示矩阵的每个格子的数

    输出描述 Output Description
    一个数,为最大值
    样例输入 Sample Input
    3 1
    1 2 3
    0 2 1
    1 4 2
    样例输出 Sample Output
    11
    数据范围及提示 Data Size & Hint
    1<=n<=50, 0<=k<=10

    这是我学了网络流之后自己写的第一道建模题,虽说这道题也是一道很普通的题。

    建图如下:很显然想到把每个点当成点,向下面的点和右边的点连边,至于权值的事情,那就把一个点拆成两个点,分为上点和下点,上点向下点连一条费用为该点点权,容量为1的边(因为每个数只能取一次),但发现取完这个数后这个点还是可以走的,那就让上点再连一条费用为0,容量为正无穷的边(表示可以走很多次)到下点。汇点显然是最后一个点的下点,至于源点的设定,因为题目中有走k次的要求,那就新创一个点,连向起点的上点,费用为0,容量为K,因为每一次取容量为1,所以取K次的意思就相当于走k条增广路。然后就求一遍最大费用流即可。建图还有一个比较烦的就是每个点编号的编排,具体编排方法下文注释上有。

      1 #include<iostream>
      2 #include<cmath>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 typedef long long LL;
      9 inline int read()    
     10 {
     11     int x=0,f=1;char c=getchar();
     12     while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
     13     while(isdigit(c)){x=x*10+c-'0';c=getchar();}
     14     return x*f;
     15 }
     16 const int oo=2147000000;
     17 const int maxn=100000;
     18 struct Edge
     19 {
     20     int u,v,f,w,next;
     21     Edge() {}
     22     Edge(int _1,int _2,int _3,int _4,int _5) : u(_1),v(_2),f(_3),w(_4),next(_5) {}
     23 }e[maxn];
     24 int n,k,first[maxn],vis[maxn],dis[maxn],a[100][100],cnt,s,t,ans;
     25 queue<int> Q;
     26 void add(int i,int a,int b,int c,int d)
     27 {
     28     e[i]=Edge(a,b,c,d,first[a]);
     29     first[a]=i;
     30 }
     31 void addEdge(int i,int a,int b,int c,int d){add(2*i,a,b,c,d);add(2*i+1,b,a,0,-d);}
     32 bool spfa()
     33 {
     34     memset(vis,0,sizeof(vis));
     35     for(int i=0;i<=2*n*n;i++)dis[i]=-oo;
     36     while(Q.size())Q.pop();
     37     dis[t]=0;vis[t]=1;Q.push(t);
     38     while(Q.size())
     39     {
     40         int now=Q.front();Q.pop();
     41         for(int i=first[now];i!=-1;i=e[i].next)
     42             if(dis[now]+e[i^1].w>dis[e[i].v] && e[i^1].f)
     43             {
     44                 dis[e[i].v]=dis[now]+e[i^1].w; 
     45                 if(!vis[e[i].v])
     46                 {
     47                     vis[e[i].v]=1;
     48                     Q.push(e[i].v);
     49                 }
     50             }
     51         vis[now]=0;
     52     }
     53     return dis[s]!=-oo;
     54 }
     55 int dfs(int x,int flow)
     56 {
     57     vis[x]=1;
     58     if(x==t)return flow;
     59     int now,used=0;
     60     for(int i=first[x];i!=-1;i=e[i].next)
     61         if(dis[e[i].v]==dis[x]-e[i].w && e[i].f && !vis[e[i].v])
     62         {
     63             now=flow-used;
     64             now=dfs(e[i].v,min(now,e[i].f));
     65             ans+=now*e[i].w;
     66             e[i].f-=now;e[i^1].f+=now;
     67             used+=now;
     68             if(used==flow)return flow;
     69         }
     70     return used;
     71 }
     72 void zkw()
     73 {
     74     while(spfa())
     75     {
     76         vis[t]=1;
     77         while(vis[t])
     78         {
     79             memset(vis,0,sizeof(vis));
     80             dfs(s,oo);
     81         } 
     82     }
     83 }
     84 int main()
     85 {
     86     memset(first,-1,sizeof(first));
     87     n=read();k=read();
     88     for(int i=0;i<n;i++)for(int j=0;j<n;j++)a[i][j]=read();
     89     for(int i=0;i<n;i++)
     90         for(int j=0;j<n;j++)
     91         {
     92             addEdge(cnt,2*(i*n+j),2*(i*n+j)+1,1,a[i][j]);cnt++;
     93             addEdge(cnt,2*(i*n+j),2*(i*n+j)+1,oo,0);cnt++;
     94             if(j!=n-1)addEdge(cnt,2*(i*n+j)+1,2*(i*n+j+1),oo,0);cnt++;//向右边 
     95             if(i!=n-1)addEdge(cnt,2*(i*n+j)+1,2*((i+1)*n+j),oo,0);cnt++;//下面 
     96         }
     97     addEdge(cnt,2*n*n,0,k,0);cnt++;
     98     s=2*n*n;t=2*n*n-1;
     99     zkw();
    100     printf("%d",ans);
    101     return 0;
    102 }
    103 /*
    104 建图:
    105 原图中a[i][j],对应编号为i*n+j,拆成两个点,一个是2*(i*n+j),另一个是2*(i*n+j)+1
    106  (i,j)上点向下点连两条边,下点向下面和右面连一条边 
    107 源点 2*n*n 向0,0连一条边 
    108 汇点 2*n*n-1 
    109 */
  • 相关阅读:
    POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)
    UVaLive 5031 Graph and Queries (Treap)
    Uva 11996 Jewel Magic (Splay)
    HYSBZ
    POJ 3580 SuperMemo (Splay 区间更新、翻转、循环右移,插入,删除,查询)
    HDU 1890 Robotic Sort (Splay 区间翻转)
    【转】ACM中java的使用
    HDU 4267 A Simple Problem with Integers (树状数组)
    POJ 1195 Mobile phones (二维树状数组)
    HDU 4417 Super Mario (树状数组/线段树)
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/6287870.html
Copyright © 2011-2022 走看看