BZOJ2095 bridge
来源:互联网 发布:mac os 10.13iso镜像 编辑:程序博客网 时间:2024/06/08 01:17
题意:
给出一个n个点m条边的无向图,每个边有一正一反两个权值;
现要从点1出发,对每条边经过且仅经过一次;
求一种方案使经过的最大权值最小;
输入:第一行为两个用空格隔开的整数n(2<=n<=1000),m(1<=m<=2000),接下来读入m行由空格隔开的4个整数a,b(1<=a,b<=n,a<>b),c,d(1<=c,d<=1000)
最大权值最小,可以二分转换为判定性问题。
这样问题就转换成了,判断是不是欧拉回路的一个问题。limit重建图。但这样问题是,图变成了一个混合图,其中有有向边也有无向边。
有向图欧拉回路:每个点indegree==outdegree
有向图欧拉回路:至多两个点的度数绝对值差1,且一个出度多、一个入度多。
无向图欧拉回路:每个点度数为偶数
无向图欧拉路:至多2个点度数为奇数。
混合图怎么办呢。。我们可以转化为有向图来做。
1.给无向边定向。
2.图不一定是个欧拉回路,我们发现把一个无向边反向,影响的度数总是±2的。所以如果出入度之差是奇数,一定不是欧拉回路。
3.每个点val=indegree-outdgree,为了维护流量平衡,把val>0的点连S,val<0的点连T,容量都为val/2.
无向边,按照定向的方向反向建边,容量1。
跑最大流看满不满流,很像无源汇有上下界可行流的做法qwq。
#include<bits/stdc++.h>using namespace std;const int MAXN=1e4+5;const int INF=1e9+7;struct edge{ int to,next,w;}e[MAXN<<2];struct data{ int u,v;}jilu[MAXN<<2];int n,m,s,t;int head[MAXN],cur[MAXN],cnt=1;inline void add(int u,int v,int w){ e[++cnt]=(edge){v,head[u],w},head[u]=cnt; e[++cnt]=(edge){u,head[v],0},head[v]=cnt;}int dep[MAXN];queue<int>q;bool bfs(int x){ memset(dep,0,sizeof(dep)); q.push(x);dep[x]=1; while(q.size()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].next){ int v=e[i].to,w=e[i].w; if(!dep[v]&&w){ dep[v]=dep[u]+1; q.push(v); } } } if(!dep[t])return 0; return 1; }int dfs(int u,int flow){ if(u==t||flow==0)return flow; for(int &i=cur[u];i;i=e[i].next){ int v=e[i].to,w=e[i].w; if(dep[v]==dep[u]+1&&w){ int tem=dfs(v,min(w,flow)); if(tem){ e[i].w-=tem;e[i^1].w+=tem; return tem; } } } return 0;}int dinic(){ int ans=0; while(bfs(s)){ for(int i=s;i<=t;i++)cur[i]=head[i]; while(int d=dfs(s,INF))ans+=d; } return ans;}int u[MAXN],v[MAXN],w1[MAXN],w2[MAXN],in[MAXN],out[MAXN],num;bool judge(int lm){ num=0; for(int i=1;i<=m;i++){ if(w1[i]<=lm)out[u[i]]++,in[v[i]]++; if(w2[i]<=lm)add(v[i],u[i],1); } for(int i=1;i<=n;i++){ in[i]=in[i]-out[i]; if(abs(in[i])&1)return 0; if(in[i]>0)add(s,i,in[i]/2),num+=in[i]/2; else if(in[i]<0)add(i,t,-in[i]/2); } if(dinic()==num)return 1; return 0;}void mem(){ memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); cnt=1;}int minn=INF,maxx=-INF;int main(){ scanf("%d%d",&n,&m); s=0,t=n+1; for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&u[i],&v[i],&w1[i],&w2[i]); if(w1[i]>w2[i])swap(w1[i],w2[i]),swap(u[i],v[i]); minn=min(minn,min(w1[i],w2[i])); maxx=max(maxx,max(w1[i],w2[i])); } int l=minn,r=maxx; while(l<=r){ mem(); int mid=(l+r)>>1; if(judge(mid))r=mid-1; else l=mid+1; } mem(); if(judge(l))printf("%d\n",l); else printf("NIE\n"); return 0;}
阅读全文