题意:有 n 点 m 边,有出发点 A 到达点 B ,只允许走原图中的最短路,但每条边只允许被走一次,问最多能找出多少条边不重复的最短路
一开始做到的时候瞎做了一发最短路,WA了之后也知道显然不对,就放着了,后来打了今年的多校,再做到的时候发现和多校第一场的1007一样的……最短路+网络流就行了,只不过第一次做这个的时候我还不知道网络流是啥,不会做也正常啦。
首先对于原图跑一遍最短路求出每个点距离 A 点的最短路,然后对于每一条边,如果它的权值等于它连接的两点的最短路的差值的时候,就说明这条路是最短路上的边,将这个边加入网络流的建图中,流量定为1表示这条边只能用一次,这样跑一遍最大流就能直接解决问题了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }