• Matrix Again HDU


    Practice link:  https://vjudge.net/problem/HDU-3376

    题意:给你一个 n*n 的矩阵,每个点有自身的权值,从左上角向右下角走只能向右或向下,从右下角向左上角走只能向左或向上,问你从左上角走向右下角再从右下角走向左上角且每个点只能走一次,问你最大权值之和是多少。

    思路:首先从右下角到左上角的过程可以转化为从左上角到右下角,那么问题就变成了从左上角到右下角的两条没有重复点的路径的最大权值和。然后看到是走矩阵且要求权值之和最大且每个格子只能走一次,就想到最大费用最大流。首先建立超级源点和超级汇点,源点到左上角的点的流量为2,费用为 0,右下角的点到汇点的流量为 2 ,费用为 0,由于每个点只能走一次,那么我们就进行拆点,即把点 k 拆成两个点 k1 和 k2,这两个点之间的流量为 1 ,费用为点 k 的权值(除了左上角和右下角的两个点的流量需要为 2)。其余可以联通的点之间的流量为 1 ,费用为 0 即可。

             最后跑一遍最大费用最大流,又因为左上角和右下角的点经过了两次,最后答案要减去这两个点的权值。

    代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<iostream>
      5 #include<string>
      6 #include<vector>
      7 #include<stack>
      8 #include<bitset>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<set>
     12 #include<list>
     13 #include<deque>
     14 #include<map>
     15 #include<queue>
     16 #define ll long long
     17 #define MOD 998244353
     18 #define INF 0x3f3f3f3f
     19 #define mem(a,x) memset(a,x,sizeof(a))
     20 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     21 using namespace std;
     22 
     23 const int maxn = 800000;
     24 
     25 bool vis[maxn];
     26 int n,m,s,t;
     27 int dis[maxn],pre[maxn],last[maxn],flow[maxn],maxflow,maxcost;
     28 
     29 struct node{
     30     int to,nxt,flow,dis;  //flow流量 dis花费
     31 }edge[4*maxn];
     32 int head[4*maxn],cnt=0;
     33 
     34 void addl(int u,int v,int flow,int dis)
     35 {
     36     edge[cnt].to=v;
     37     edge[cnt].flow=flow;
     38     edge[cnt].dis=dis;
     39     edge[cnt].nxt=head[u];
     40     head[u]=cnt++;
     41 }
     42 
     43 bool spfa(int s,int t)
     44 {
     45     for(int i=0;i<=2*n*n+1;i++){
     46         dis[i]=-1;
     47         flow[i]=INF;
     48         vis[i]=0;
     49     }
     50     queue<int>q;
     51     q.push(s);
     52     vis[s]=1;
     53     dis[s]=0;
     54     pre[t]=-1;
     55     while(!q.empty()){
     56         int now=q.front();
     57         q.pop();
     58         vis[now]=0;
     59         for(int i=head[now];i!=-1;i=edge[i].nxt)
     60         {
     61             if(edge[i].flow>0&&dis[edge[i].to]<dis[now]+edge[i].dis)
     62             {
     63                 dis[edge[i].to]=dis[now]+edge[i].dis;
     64                 pre[edge[i].to]=now;
     65                 last[edge[i].to]=i;
     66                 flow[edge[i].to]=min(flow[now],edge[i].flow);
     67                 if(!vis[edge[i].to])
     68                 {
     69                     vis[edge[i].to]=1;
     70                     q.push(edge[i].to);
     71                 }
     72             }
     73         }
     74     }
     75     return pre[t]!=-1;
     76 }
     77 void MCMF()
     78 {
     79     while(spfa(s,t))
     80     {
     81         int now=t;
     82         maxflow+=flow[t];
     83         maxcost+=flow[t]*dis[t];
     84         while(now!=s)
     85         {
     86             edge[last[now]].flow-=flow[t];
     87             edge[last[now]^1].flow+=flow[t];
     88             now=pre[now];
     89         }
     90     }
     91 }
     92 int mp[605][605];
     93 int main()
     94 {
     95     while (scanf("%d",&n)!=EOF) {
     96         mem(head,-1);
     97         mem(pre,-1);
     98         cnt=0;
     99         maxflow=0;
    100         maxcost=0;
    101         s=0;
    102         t=2*n*n+1;
    103         addl(s,1,2,0);
    104         addl(1,s,0,0);
    105         for(int i=1;i<=n;i++){
    106             for(int j=1;j<=n;j++){
    107                 scanf("%d",&mp[i][j]);
    108                 int num=(i-1)*n+j;
    109                 if(i==j&&(num==1||num==n*n)){
    110                     addl(num,num+n*n,2,mp[i][j]);
    111                     addl(num+n*n,num,0,-mp[i][j]);
    112                 }else{
    113                     addl(num+n*n,num,0,-mp[i][j]);
    114                     addl(num,num+n*n,1,mp[i][j]);
    115                 }
    116                 if(i+1<=n){
    117                     addl(num+n*n,i*n+j,1,0);
    118                     addl(i*n+j,num+n*n,0,0);
    119                 }
    120                 if(j+1<=n){
    121                     addl(num+n*n,num+1,1,0);
    122                     addl(num+1,num+n*n,0,0);
    123                 }
    124             }
    125         }
    126         addl(2*n*n,t,2,0);
    127         addl(t,2*n*n,0,0);
    128         MCMF();
    129         printf("%d
    ",maxcost-mp[1][1]-mp[n][n]);
    130     }
    131     return 0;
    132 }
    越自律,越自由
  • 相关阅读:
    20Spring_JdbcTemplatem模板工具类
    19Spring_AOP编程(AspectJ)_使用@Pointcut注解来定义切点
    18Spring_AOP编程(AspectJ)_AspectJ的各种通知总结
    17Spring_AOP编程(AspectJ)_AspectJ的注解编程
    14Spring_AOP编程(AspectJ)_环绕通知
    android ViewPager滑动事件讲解
    为listview的item中的元素设置onclick事件
    Android EditText光标颜色 与inputType
    【Android】Android内存溢出问题---用自行开辟的空间进行对内存管理
    【Android】eclipse打不开的解决办法和“Jar mismatch! Fix your dependencies”的解决
  • 原文地址:https://www.cnblogs.com/ha-chuochuo/p/13543664.html
Copyright © 2020-2023  润新知