题意:有 n 点 m 边,有出发点 A 到达点 B ,只允许走原图中的最短路,但每条边只允许被走一次,问最多能找出多少条边不重复的最短路

一开始做到的时候瞎做了一发最短路,WA了之后也知道显然不对,就放着了,后来打了今年的多校,再做到的时候发现和多校第一场的1007一样的……最短路+网络流就行了,只不过第一次做这个的时候我还不知道网络流是啥,不会做也正常啦。

首先对于原图跑一遍最短路求出每个点距离 A 点的最短路,然后对于每一条边,如果它的权值等于它连接的两点的最短路的差值的时候,就说明这条路是最短路上的边,将这个边加入网络流的建图中,流量定为1表示这条边只能用一次,这样跑一遍最大流就能直接解决问题了。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<queue>
  5 #include<vector>
  6 using namespace std;
  7 typedef pair<int,int> pii;
  8 const int maxm=1005;
  9 const int INF=0x3f3f3f3f;
 10 
 11 struct cmp{
 12     bool operator()(pii a,pii b){
 13         return a.first>b.first;
 14     }
 15 };
 16 
 17 int head[1005],point[100005],val[100005],nxt[100005],size;
 18 bool vis[100005];
 19 int dis[1005],n,s,p,fa[1005],pa[1005];
 20 
 21 
 22 struct edge{             //弧的结构体,变量:弧的出发点、结束点、容量、流量
 23     int from,to,c,f;
 24     edge(int a,int b,int m,int n):from(a),to(b),c(m),f(n){}
 25 };
 26 
 27 struct dinic{
 28     int m,s,t;                    //边数、源点标号、汇点标号
 29     vector<edge>e;        //
 30     vector<int>g[maxm];    //g[i][j]表示第i个点出发的第j条边在e中的编号
 31     bool vis[maxm];
 32     int d[maxm],cur[maxm];    //d为源点到点的距离,cur为当前遍历到的边
 33     void init(int n){                //初始化,n为点数量(标号0~n-1)
 34         for(int i=0;i<n+5;i++)g[i].clear();
 35         e.clear();
 36     }
 37     void add(int a,int b,int v){        //加入弧和反向弧
 38         e.push_back(edge(a,b,v,0));    //正向弧容量v,反向弧容量0
 39         e.push_back(edge(b,a,0,0));
 40         m=e.size();
 41         g[a].push_back(m-2);
 42         g[b].push_back(m-1);
 43     }
 44     bool bfs(){
 45         memset(vis,0,sizeof(vis));
 46         queue<int>q;
 47         q.push(s);
 48         d[s]=0;
 49         vis[s]=1;
 50         while(!q.empty()){
 51             int u=q.front();q.pop();
 52             for(int i=0;i<g[u].size();i++){
 53                 edge tmp=e[g[u][i]];
 54                 if(!vis[tmp.to]&&tmp.c>tmp.f){
 55                     vis[tmp.to]=1;
 56                     d[tmp.to]=d[u]+1;
 57                     q.push(tmp.to);
 58                 }
 59             }
 60         }
 61         return vis[t];
 62     }
 63     int dfs(int x,int a){
 64         if(x==t||a==0)return a;
 65         int flow=0,f;
 66         for(int& i=cur[x];i<g[x].size();i++){
 67             edge &tmp=e[g[x][i]];
 68             if(d[x]+1==d[tmp.to]&&(f=dfs(tmp.to,min(a,tmp.c-tmp.f)))>0){
 69                 tmp.f+=f;
 70                 e[g[x][i]^1].f-=f;
 71                 flow+=f;
 72                 a-=f;
 73                 if(a==0)break;
 74             }
 75         }
 76         if(!flow)d[x]=-1;
 77         return flow;
 78     }
 79     int mf(int s,int t){                //在主函数中使用的函数,求s到t的最大流
 80         this->s=s;
 81         this->t=t;
 82         int flow=0;
 83         while(bfs()){
 84             memset(cur,0,sizeof(cur));
 85             flow+=dfs(s,INF);
 86         }
 87         return flow;
 88     }
 89 };
 90 
 91 void add(int a,int b,int v){
 92     point[size]=b;
 93     val[size]=v;
 94     nxt[size]=head[a];
 95     head[a]=size++;
 96 }
 97 
 98 void dij(){
 99     int i;
100     priority_queue<pii,vector<pii>,cmp>q;
101     memset(dis,0x3f,sizeof(dis));
102     memset(fa,-1,sizeof(fa));
103     dis[s]=0;
104     q.push(make_pair(dis[s],s));
105     while(!q.empty()){
106         pii u=q.top();
107         q.pop();
108         if(u.first>dis[u.second])continue;
109         for(i=head[u.second];~i;i=nxt[i]){
110             int j=point[i],v=u.first+val[i];
111             if(!vis[i]&&dis[j]>v){
112                 dis[j]=v;
113                 fa[j]=u.second;
114                 pa[j]=i;
115                 q.push(make_pair(dis[j],j));
116             }
117         }
118     }
119 }
120 
121 int main(){
122     int t;
123     scanf("%d",&t);
124     for(int q=1;q<=t;q++){
125         int m,i;
126         memset(head,-1,sizeof(head));
127         memset(vis,0,sizeof(vis));
128         size=0;
129         scanf("%d%d",&n,&m);
130         for(i=1;i<=m;i++){
131             int a,b,v;
132             scanf("%d%d%d",&a,&b,&v);
133             if(a!=b){
134                 add(a,b,v);
135             }
136         }
137         scanf("%d%d",&s,&p);
138         dinic d;
139         dij();
140         for(i=1;i<=n;++i){
141             for(int j=head[i];~j;j=nxt[j]){
142                 int k=point[j];
143                 if(dis[i]+val[j]==dis[k])d.add(i,k,1);
144             }
145         }
146         printf("%d\n",d.mf(s,p));
147     }
148     return 0;
149 }
View Code