zoukankan      html  css  js  c++  java
  • ZOJ 2760

    人老了就比较懒,故意挑了到看起来很和蔼的题目做,然后套个spfa和dinic的模板WA了5发,人老了,可能不适合这种刺激的竞技运动了……

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2760

    Description

    Given a weighted directed graph, we define the shortest path as the path who has the smallest length among all the path connecting the source vertex to the target vertex. And if two path is said to be non-overlapping, it means that the two path has no common edge. So, given a weighted directed graph, a source vertex and a target vertex, we are interested in how many non-overlapping shortest path could we find out at most.

    Input

    Input consists of multiple test cases. The first line of each test case, there is an integer number N (1<=N<=100), which is the number of the vertices. Then follows an N * N matrix, represents the directed graph. Each element of the matrix is either non-negative integer, denotes the length of the edge, or -1, which means there is no edge. At the last, the test case ends with two integer numbers S and T (0<=S, T<=N-1), that is, the starting and ending points. Process to the end of the file.

    Output

    For each test case, output one line, the number of the the non-overlapping shortest path that we can find at most, or "inf" (without quote), if the starting point meets with the ending.

    Sample Input

    4
    0 1 1 -1
    -1 0 1 1
    -1 -1 0 1
    -1 -1 -1 0
    0 3
    5
    0 1 1 -1 -1
    -1 0 1 1 -1
    -1 -1 0 1 -1
    -1 -1 -1 0 1
    -1 -1 -1 -1 0
    0 4

    Sample Output

    2
    1

    呃,题意和思路什么的直接看宝典吧:

    当然啦,没必要一定像他那样ds[i]+edge[i][j]+dt[j]==ds[t]这样,我们要抓住精髓,看清本质,只要保证剌进来的边属于最短路上的边就行,

    所以,只要做一次spfa,然后满足d[i]+edge[i][j]==d[j]就行。

                                                                       某只A题A的神志不清的博主的心灵独白                                                                   begin

    然后联想到前面那题POJ1637的构图,不难发现,在integer的情况下把edge.cap设为1,可以代表一种这条边到底走不走的意义,然后全图都设为1的话,最大流大概就是……

    从source到target最多有几条不相交的简单路径可走……

    嗯,如果这个图上的边全是属于最短路的边的话,那么这个最大流就是本题的答案了……诶等下,再联想到dinic的BFS过程是找层次图,而层次图从某种意义上来讲就是最短路图?

    所以我们可以用一个计算层次的BFS来代替SPFA?我好想发现了什么??让我来再码一发(然而spfa本来不就是个BFS么……

    然后,我立马就发现……dinic里的BFS是建立在边长默认为1的情况下的,所以我立马就放弃了我TM真是个傻子……

                                                                       某只A题A的神志不清的博主的心灵独白                                                                   end


    呃,先忽略我的心灵独白,看跟现在市面上比较相像的代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 #define MAXN 103
      5 #define INF 0x3f3f3f3f
      6 using namespace std;
      7 int n,s,t;
      8 int d[MAXN],map[MAXN][MAXN];
      9 bool vis[MAXN];
     10 void spfa(int st)
     11 {
     12     for(int i=0;i<n;i++){
     13         i==st ? d[i]=0 : d[i]=INF;
     14         vis[i]=0;
     15     }
     16     queue<int> q;
     17     q.push(st);
     18     vis[st]=1;
     19     while(!q.empty())
     20     {
     21         int u=q.front();q.pop();vis[u]=0;
     22         for(int v=0;v<n;v++)
     23         {
     24             if(u==v || map[u][v]==-1) continue;
     25             int tmp=d[v];
     26             if(d[v]>d[u]+map[u][v]) d[v]=d[u]+map[u][v];
     27             if(d[v]<tmp && !vis[v]) q.push(v),vis[v]=1;
     28         }
     29     }
     30 }
     31 
     32 struct Edge{
     33     int u,v,c,f;
     34 }; 
     35 struct Dinic
     36 {
     37     vector<Edge> E;
     38     vector<int> G[MAXN];
     39     bool vis[MAXN]; //BFS使用
     40     int lev[MAXN];//记录层次 
     41     int cur[MAXN]; //当前弧下标
     42     void init(int n)
     43     {
     44         E.clear();
     45         for(int i=0;i<n;i++) G[i].clear();
     46     }
     47     void addedge(int from,int to,int cap)
     48     {
     49         E.push_back((Edge){from,to,cap,0});
     50         E.push_back((Edge){to,from,0,0});
     51         int m=E.size(); 
     52         G[from].push_back(m-2);
     53         G[to].push_back(m-1);
     54     }
     55     bool bfs()
     56     {
     57         memset(vis,0,sizeof(vis));
     58         queue<int> q;
     59         q.push(s);
     60         lev[s]=0;
     61         vis[s]=1;
     62         while(!q.empty())
     63         {
     64             int now=q.front(); q.pop();
     65             for(int i=0;i<G[now].size();i++)
     66             {
     67                 Edge edge=E[G[now][i]];
     68                 int nex=edge.v;
     69                 if(!vis[nex] && edge.c>edge.f)//属于残存网络的边
     70                 {
     71                     lev[nex]=lev[now]+1;
     72                     q.push(nex);
     73                     vis[nex]=1;
     74                 }
     75             }
     76         }
     77         return vis[t];
     78     }
     79     int dfs(int now,int aug)//now表示当前结点,aug表示目前为止的最小残量
     80     {
     81         if(now==t || aug==0) return aug;//aug等于0时及时退出,此时相当于断路了
     82         int flow=0,f;
     83         for(int& i=cur[now];i<G[now].size();i++)//从上次考虑的弧开始,注意要使用引用,同时修改cur[now]
     84         {
     85             Edge& edge=E[G[now][i]];
     86             int nex=edge.v;
     87             if(lev[now]+1 == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>0)
     88             {
     89                 edge.f+=f;
     90                 E[G[now][i]^1].f-=f;
     91                 flow+=f;
     92                 aug-=f;
     93                 if(!aug) break;//aug等于0及时退出,当aug!=0,说明当前节点还存在另一个增广路分支
     94             }
     95         }
     96         return flow;
     97     }
     98     int maxflow()//主过程
     99     {
    100         int flow=0;
    101         while(bfs())//不停地用bfs构造分层网络,然后用dfs沿着阻塞流增广
    102         {
    103             memset(cur,0,sizeof(cur));
    104             flow+=dfs(s,INF);
    105         }
    106         return flow;
    107     }
    108 }dinic;
    109 
    110 int main()
    111 {
    112     while(scanf("%d",&n)!=EOF)
    113     {
    114         for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&map[i][j]);
    115         scanf("%d%d",&s,&t);
    116         if(s==t)
    117         {
    118             printf("inf
    ");
    119             continue;
    120         }
    121         spfa(s);
    122         dinic.init(n);
    123         for(int i=0;i<n;i++)
    124             for(int j=0;j<n;j++)
    125                 if(i!=j && map[i][j]!=-1 && d[i]!=INF && d[j]!=INF && d[i]+map[i][j]==d[j]) dinic.addedge(i,j,1);
    126         printf("%d
    ",dinic.maxflow());
    127     }
    128 }

    (dinic模板的中文注释懒得去掉了,反正看起来不多,到时候忘记了过程还可以看看注释回忆回忆……)

  • 相关阅读:
    [System.currentTimeMillis]/[Calendar.getInstance().getTimeInMillis()]/[new Date().getTime()]
    [Maven]告警[WARNING] Unable to create Maven project from repository.
    通过设置JDK解决存在多个Gradle后台进程的问题
    使用OpenSSL实现X25519秘钥协商功能
    C++代码质量度量工具大阅兵
    Java代码质量度量工具大阅兵
    计算两个时间的时间差(天、小时、分钟、秒数)
    上传文件进度条 (已上传大小、总大小、速度、剩余时间、已用时间)
    table 表格自适应
    谷歌浏览器input框添加了黄色 背景色
  • 原文地址:https://www.cnblogs.com/dilthey/p/7384370.html
Copyright © 2011-2022 走看看