题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416
题目大意:有n座城市m条单向边。问从A城市到B城市有多少种走法,每条边只能经过一次。
思路:我们跑出最短路图,建图流量为1,然后直接最短流。
#include<bits/stdc++.h> #define LL long long using namespace std; const LL maxn=100005; const LL INF=10000000000000000; LL d[maxn], cur[maxn], start, tend; struct node { LL to, cap, next; } edge[maxn << 1]; LL head[maxn]; LL cnt; void addedge(LL start, LL to, LL cap) { edge[cnt].to = to; edge[cnt].cap = cap; edge[cnt].next = head[start]; head[start] = cnt++; } bool BFS() { //memset(vis,false,sizeof(vis)); memset(d, -1, sizeof(LL)*1005); LL Q[maxn * 2]; LL Thead, Ttail; Thead = Ttail = 0; Q[Ttail++] = start;; d[start] = 0; //vis[start]=1; while (Thead<Ttail) { LL x = Q[Thead]; if (x == tend) return true; for (LL i = head[x]; i != -1; i = edge[i].next) { LL temp = edge[i].to; if (d[temp] == -1 && edge[i].cap>0)//没有标记,且可行流大于0 { //vis[temp.to]=true; d[temp] = d[x] + 1; Q[Ttail++] = temp; } } Thead++; } return false;//汇点是否成功标号,也就是说是否找到增广路 } LL DFS(LL x, LL cap) { if (x == tend) return cap; //vis[start]=true; LL flow = 0, f; for (LL i = head[x]; i != -1; i = edge[i].next) { LL temp = edge[i].to; //if(temp.cap<=0||vis[temp.to])continue; if (d[temp] == d[x] + 1 && edge[i].cap) { f = DFS(temp, min(cap - flow, edge[i].cap)); edge[i].cap -= f; edge[i ^ 1].cap += f; flow += f; if (flow == cap) break; } } if (!flow) d[x] = -2;//防止重搜 return flow; } LL maxflow() { LL flow = 0, f; while (BFS()) { //memset(vis,false,sizeof(vis)); while ((f = DFS(start, INF))>0) flow += f; } return flow; } vector< pair<LL ,LL > > e1[maxn], e2[maxn]; LL n, m; LL dis[maxn]; //dis当前的最短路 LL vis[maxn]; //是否已经求出最短路 LL dis2[maxn]; //dis当前的最短路 LL vis2[maxn]; //是否已经求出最短路 LL xx[maxn], yy[maxn], zz[maxn]; priority_queue<pair<LL, LL> > q; LL dijkstra(LL s, LL t) { while(!q.empty()) { q.pop(); } dis[s]=0; q.push(make_pair(-dis[s], s)); while(!q.empty()) { LL now=q.top().second; //一定是最短路上的顶点 q.pop(); if(vis[now]) { continue; } vis[now]=1; for(LL i=0;i<e1[now].size();i++) //访问所有的邻接点 { LL v=e1[now][i].first; if(!vis[v]&&dis[v]>dis[now]+e1[now][i].second) { dis[v]=dis[now]+e1[now][i].second; q.push(make_pair(-dis[v], v));//把可能的最短路顶点加入队列 } } } if(dis[t]==INF) { return -1; //s-t没有通路 } else { return dis[t]; } } LL dijkstra2(LL s, LL t) { memset(vis, 0 ,sizeof(vis)); while(!q.empty()) { q.pop(); } dis2[s]=0; q.push(make_pair(-dis2[s], s)); while(!q.empty()) { LL now=q.top().second; //一定是最短路上的顶点 q.pop(); if(vis[now]) { continue; } vis[now]=1; for(LL i=0;i<e2[now].size();i++) //访问所有的邻接点 { LL v=e2[now][i].first; if(!vis[v]&&dis2[v]>dis2[now]+e2[now][i].second) { dis2[v]=dis2[now]+e2[now][i].second; q.push(make_pair(-dis2[v], v));//把可能的最短路顶点加入队列 } } } if(dis2[t]==INF) { return -1; //s-t没有通路 } else { return dis2[t]; } } int main() { LL t; scanf("%lld",&t); while(t--) { LL n, m; scanf("%lld%lld",&n,&m); for(LL i=0;i<maxn;i++) //初始化 { vis[i]=0; dis[i]=INF; dis2[i]=INF; e1[i].clear(); e2[i].clear(); } for(LL i=0;i<m;i++) { LL x, y, z; scanf("%lld%lld%lld",&x,&y,&z); xx[i]=x, yy[i]=y, zz[i]=z; e1[x].push_back(make_pair(y ,z)); e2[y].push_back(make_pair(x ,z)); } scanf("%lld%lld", &start, &tend); dijkstra(start, tend); dijkstra2(tend, start); cnt = 0; memset(head, -1, sizeof(head)); for(LL i=0; i<=m; i++) { LL u=xx[i], v=yy[i], w=zz[i]; if(dis[u]+dis2[v]+w==dis[tend]) { addedge(u, v, 1); addedge(v, u, 0); } } cout<<maxflow()<<endl; } return 0; }