目录
显示
题目链接
https://www.luogu.org/problem/P1344
题解
容易看出本题的目标是求出最小割,但如何确保在求得最小割的情况下割掉的边数最小呢?
考虑将边数这一要素加入到流量当中去。我们将原来每条边的流量乘上 \(1001\),然后再加 \(1\)。
因为最多只有 \(1000\) 条边,这意味着:
- 可以将答案的低位视为 \(1001\) 进制数,割掉的边数不会影响到最小割值的计算(即低位不会产生进位);
- 答案的高位即为最小割,低位为要割掉的边数。
#include <cstring> #include <iostream> #include <algorithm> #include <queue> #define INF 0x3f3f3f3f using namespace std; struct edge { int v,w,next; }e[2005]; int head[35],cur[35],dist[35],vis[35],cnt=1,n,m; void addedge(int u,int v,int w) { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } bool bfs() { queue<int> q; memset(dist,INF,sizeof(dist)); memcpy(cur,head,sizeof(head)); dist[1]=0,vis[1]=1; q.push(1); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].v; if(e[i].w&&dist[v]>dist[u]+1) { dist[v]=dist[u]+1; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dist[n]!=INF; } int dfs(int u,int flow) { if(u==n)return flow; int used=0; for(int i=cur[u];i;i=e[i].next) { cur[u]=i; int v=e[i].v; if(e[i].w&&dist[v]==dist[u]+1) { int w=dfs(v,min(flow-used,e[i].w)); used+=w; e[i].w-=w; e[i^1].w+=w; if(used==flow)break; } } return used; } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { int u,v,w; cin>>u>>v>>w; addedge(u,v,w*1001+1); addedge(v,u,0); } long long ans=0; while(bfs()) ans+=dfs(1,INF); cout<<ans/1001<<" "<<ans%1001<<endl; return 0; }