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 */
  • 相关阅读:
    非对称加密-RSA公钥加密,私钥解密,私钥加签,公钥验签
    设置mysql数据库本地连接或外部可连接
    mysql自增长主键,删除数据后,将主键顺序重新排序
    非Service层和Controller层调用ssm框架中的方法
    DES加密算法(密文只有字符串和数字)java和android加密的结果一致(可放在url中)
    SpringBoot ajax Restful整合
    java中线程执行流程详解
    在 CSS 中直接引用 fontawesome 图标(附码表)
    C++内存管理~
    操作系统那些事儿
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/6287870.html
Copyright © 2011-2022 走看看