您的位置:首页 > 理论基础 > 计算机网络

HDU 4280 Island Transport [平面图网络流]

2012-09-14 10:26 357 查看
  平面图网络流,比赛的时候想不到怎么建对偶图试了试dinic,居然水过去了。。数据是真水。。

  赛后看了各牛的解题报告,才搞懂怎么建对偶图,确实是很巧妙。关于对偶图的概念,可以去看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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: