题意:有 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 }
时间: 2024-12-09 20:28:08