HDU 4280 Island Transport [平面图网络流]
2012-09-14 10:26
357 查看
平面图网络流,比赛的时候想不到怎么建对偶图试了试dinic,居然水过去了。。数据是真水。。
赛后看了各牛的解题报告,才搞懂怎么建对偶图,确实是很巧妙。关于对偶图的概念,可以去看08年周东的论文《两极相通——浅析最大—最小定理在信息学竞赛中的应用》。
建对偶图的难点在于确定每条边相邻的是哪两个块,过程可分为四步
1、将无向图的每条边拆为两条有向边,然后扫描所有的点,将某边对于该点的入边ID和出边ID以及极角存起来。注意起点和终点之间也要连一条边。
2、将与该点相连的边按照极角排序,每条边的入边ID的next指向下一条边的出边ID。不难发现,这样操作以后,每个块周围的边形成了一个环,并且一条无向边的两条正向边属于相邻的两个块。
3、扫描一遍所有的边,通过next数组可以标记出哪些边属于同一个块。
4、一条无向边的两条有向边属于相邻的两个块,建立对偶图,用最短路求解。
赛后看了各牛的解题报告,才搞懂怎么建对偶图,确实是很巧妙。关于对偶图的概念,可以去看08年周东的论文《两极相通——浅析最大—最小定理在信息学竞赛中的应用》。
建对偶图的难点在于确定每条边相邻的是哪两个块,过程可分为四步
1、将无向图的每条边拆为两条有向边,然后扫描所有的点,将某边对于该点的入边ID和出边ID以及极角存起来。注意起点和终点之间也要连一条边。
2、将与该点相连的边按照极角排序,每条边的入边ID的next指向下一条边的出边ID。不难发现,这样操作以后,每个块周围的边形成了一个环,并且一条无向边的两条正向边属于相邻的两个块。
3、扫描一遍所有的边,通过next数组可以标记出哪些边属于同一个块。
4、一条无向边的两条有向边属于相邻的两个块,建立对偶图,用最短路求解。
#include <string.h> #include <stdio.h> #include <vector> #include <algorithm> #include <queue> #include <math.h> #define INF 0x3fffffff #define MAXN 100005 using namespace std; const double PI=acos(-1.0); struct pnt{int x,y;}p[MAXN]; struct edge{int v,w,n;}e[MAXN*2]; double eps=1e-8; inline int dcmp(const double &x){return (x>eps)-(x<-eps);} struct v_edge{ int in,out; double arg; v_edge(int f,int b,double args):in(f),out(b),arg(args){}; bool operator <(const v_edge& e)const{ return dcmp(arg-e.arg)==-1; } }; vector<v_edge> vec[MAXN]; int cas,n,m,s,t,tu,tv,es; int cap[MAXN],first[MAXN],ess;; int next[MAXN*2],col[MAXN*2],cols; inline void addedge(int &u,int &v,int &w){ e[ess].v=v,e[ess].w=w,e[ess].n=first[u],first[u]=ess++; } void makegraph(){ es=ess=0; for(int i=1;i<=n;i++)vec[i].clear(); //读入边并建图,存极角以便按极角排序 for(int i=0;i<m;i++){ scanf("%d%d%d",&tu,&tv,&cap[i]); if(tu==tv)continue; double argv=atan2((double)p[tv].y-p[tu].y,(double)p[tv].x-p[tu].x); double argu=atan2((double)p[tu].y-p[tv].y,(double)p[tu].x-p[tv].x); vec[tu].push_back(v_edge(es<<1,es<<1|1,argv)); vec[tv].push_back(v_edge(es<<1|1,es<<1,argu)); es++; } //起点和终点之间要加一条边并保证在最外面 cap[es]=INF; vec[s].push_back(v_edge(es<<1,es<<1|1,PI)); vec[t].push_back(v_edge(es<<1|1,es<<1,0)); es++; //求出每条边按逆时针方向的next边 for(int i=1;i<=n;i++){ int size=vec[i].size(); sort(vec[i].begin(),vec[i].end()); for(int j=0;j<size-1;j++)next[vec[i][j].in]=vec[i][j+1].out; next[vec[i][size-1].in]=vec[i][0].out; } //将边分到对应的块中 memset(col,-1,es*8);cols=0; for(int i=0;i<es*2;i++){ if(col[i]!=-1)continue; ++cols; int tt=i; for(tt=i;next[tt]!=i;tt=next[tt])col[tt]=cols; col[tt]=cols; } //建立对偶图 memset(first,-1,(cols+1)*4); for(int i=0;i<es;i++){ addedge(col[i<<1],col[i<<1|1],cap[i]); addedge(col[i<<1|1],col[i<<1],cap[i]); } } //---dijkstra--- typedef pair<int,int> pii; int d[MAXN]; bool cal[MAXN]; int dijkstra(int st,int en,int totn){ priority_queue<pii,vector<pii>,greater<pii> > q; for(int i=0;i<=totn;i++){ d[i]=(i==st?0:INF); cal[i]=0; } q.push(make_pair(d[st],st)); while(!q.empty()){ pii pi=q.top();q.pop(); int u=pi.second; if(u==en)return d[en]; if(cal[u])continue; cal[u]=true; for(int i=first[u];i!=-1;i=e[i].n){ int v=e[i].v; if(d[v]>d[u]+e[i].w){ d[v]=d[u]+e[i].w; q.push(make_pair(d[v],v)); } } } return d[en]; } int main(){ for(scanf("%d",&cas);cas--;){ scanf("%d%d",&n,&m); s=t=1; for(int i=1;i<=n;i++){ scanf("%d%d",&p[i].x,&p[i].y); if(p[i].x<p[s].x)s=i; if(p[i].x>p[t].x)t=i; } makegraph(); int ans=dijkstra(col[(es-1)<<1|1],col[(es-1)<<1],cols); printf("%d\n",ans); } return 0; }
相关文章推荐
- HDU 4280 Island Transport(网络流)
- hdu 4280 Island Transport 【网络流+优化】
- hdu 4280 Island Transport 【图论-网络流-ISAP+栈优化】
- HDU 4280 Island Transport 网络流裸题
- HDU 4280 Island Transport 网络流
- 平面图网络流(poj 2822 & hdu 4280 )
- HDU 4280 Island Transport(网络流)
- HDU 4280 Island Transport(网络流)
- hdu 4280 网络流 sap 点边数据很大
- HDU 4280 Island Transport(网络流,SAP)
- HDU 4280 Island Transport (网络流)
- HDU 4280 网络流(ISAP || Dinic)
- Island Transport HDU - 4280 (无向图形网络流)
- HDU 4280 网络流SAP版
- HDU 4280 Island Transport (网络流 sap)
- HDU 4280 Island Transport 网络流sap
- hdu 4280 网络流
- HDU 4280 Island Transport(网络流)
- HDU 4280 Island Transport(网络流,最大流)
- hdu4280 网络流+挂(无向图的网络流注意建边)