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


      平面图网络流,比赛的时候想不到怎么建对偶图试了试dinic,居然水过去了。。数据是真水。。

      赛后看了各牛的解题报告,才搞懂怎么建对偶图,确实是很巧妙。关于对偶图的概念,可以去看08年周东的论文《两极相通——浅析最大—最小定理在信息学竞赛中的应用》。

      建对偶图的难点在于确定每条边相邻的是哪两个块,过程可分为四步

      1、将无向图的每条边拆为两条有向边,然后扫描所有的点,将某边对于该点的入边ID和出边ID以及极角存起来。注意起点和终点之间也要连一条边。

      2、将与该点相连的边按照极角排序,每条边的入边ID的next指向下一条边的出边ID。不难发现,这样操作以后,每个块周围的边形成了一个环,并且一条无向边的两条正向边属于相邻的两个块。

      3、扫描一遍所有的边,通过next数组可以标记出哪些边属于同一个块。

      4、一条无向边的两条有向边属于相邻的两个块,建立对偶图,用最短路求解。

      

      1 #include <string.h>
      2 #include <stdio.h>
      3 #include <vector>
      4 #include <algorithm>
      5 #include <queue>
      6 #include <math.h>
      7 #define INF 0x3fffffff
      8 #define MAXN 100005
      9 using namespace std;
     10 const double PI=acos(-1.0);
     11 struct pnt{int x,y;}p[MAXN];
     12 struct edge{int v,w,n;}e[MAXN*2];
     13 double eps=1e-8;
     14 inline int dcmp(const double &x){return (x>eps)-(x<-eps);}
     15 struct v_edge{
     16     int in,out;
     17     double arg;
     18     v_edge(int f,int b,double args):in(f),out(b),arg(args){};
     19     bool operator <(const v_edge& e)const{
     20         return dcmp(arg-e.arg)==-1;
     21     }
     22 };
     23 vector<v_edge> vec[MAXN];
     24 int cas,n,m,s,t,tu,tv,es;
     25 int cap[MAXN],first[MAXN],ess;;
     26 int next[MAXN*2],col[MAXN*2],cols;
     27 inline void addedge(int &u,int &v,int &w){
     28     e[ess].v=v,e[ess].w=w,e[ess].n=first[u],first[u]=ess++;
     29 }
     30 void makegraph(){
     31     es=ess=0;
     32     for(int i=1;i<=n;i++)vec[i].clear();
     33     //读入边并建图,存极角以便按极角排序
     34     for(int i=0;i<m;i++){
     35         scanf("%d%d%d",&tu,&tv,&cap[i]);
     36         if(tu==tv)continue;
     37         double argv=atan2((double)p[tv].y-p[tu].y,(double)p[tv].x-p[tu].x);
     38         double argu=atan2((double)p[tu].y-p[tv].y,(double)p[tu].x-p[tv].x);
     39         vec[tu].push_back(v_edge(es<<1,es<<1|1,argv));
     40         vec[tv].push_back(v_edge(es<<1|1,es<<1,argu));
     41         es++;
     42     }
     43     //起点和终点之间要加一条边并保证在最外面
     44     cap[es]=INF;
     45     vec[s].push_back(v_edge(es<<1,es<<1|1,PI));
     46     vec[t].push_back(v_edge(es<<1|1,es<<1,0));
     47     es++;
     48     //求出每条边按逆时针方向的next边
     49     for(int i=1;i<=n;i++){
     50         int size=vec[i].size();
     51         sort(vec[i].begin(),vec[i].end());
     52         for(int j=0;j<size-1;j++)next[vec[i][j].in]=vec[i][j+1].out;
     53         next[vec[i][size-1].in]=vec[i][0].out;
     54     }
     55     //将边分到对应的块中
     56     memset(col,-1,es*8);cols=0;
     57     for(int i=0;i<es*2;i++){
     58         if(col[i]!=-1)continue;
     59         ++cols;
     60         int tt=i;
     61         for(tt=i;next[tt]!=i;tt=next[tt])col[tt]=cols;
     62         col[tt]=cols;
     63     }
     64     //建立对偶图
     65     memset(first,-1,(cols+1)*4);
     66     for(int i=0;i<es;i++){
     67         addedge(col[i<<1],col[i<<1|1],cap[i]);
     68         addedge(col[i<<1|1],col[i<<1],cap[i]);
     69     }
     70 }
     71 //---dijkstra---
     72 typedef pair<int,int> pii;
     73 int d[MAXN];
     74 bool cal[MAXN];
     75 int dijkstra(int st,int en,int totn){
     76     priority_queue<pii,vector<pii>,greater<pii> > q;
     77     for(int i=0;i<=totn;i++){
     78         d[i]=(i==st?0:INF);
     79         cal[i]=0;
     80     }
     81     q.push(make_pair(d[st],st));
     82     while(!q.empty()){
     83         pii pi=q.top();q.pop();
     84         int u=pi.second;
     85         if(u==en)return d[en];
     86         if(cal[u])continue;
     87         cal[u]=true;
     88         for(int i=first[u];i!=-1;i=e[i].n){
     89             int v=e[i].v;
     90             if(d[v]>d[u]+e[i].w){
     91                 d[v]=d[u]+e[i].w;
     92                 q.push(make_pair(d[v],v));
     93             }
     94         }
     95     }
     96     return d[en];
     97 }
     98 int main(){
     99     for(scanf("%d",&cas);cas--;){
    100         scanf("%d%d",&n,&m);
    101         s=t=1;
    102         for(int i=1;i<=n;i++){
    103             scanf("%d%d",&p[i].x,&p[i].y);
    104             if(p[i].x<p[s].x)s=i;
    105             if(p[i].x>p[t].x)t=i;
    106         }
    107         makegraph();
    108         int ans=dijkstra(col[(es-1)<<1|1],col[(es-1)<<1],cols);
    109         printf("%d\n",ans);
    110     }
    111     return 0;
    112 }
  • 相关阅读:
    雷军复盘小米下滑原因:线上遭恶性竞争 线下错过县乡市场(小米是手机公司,也是移动互联网公司,更是新零售公司)
    Web前端开发人员实用Chrome插件收集
    批量删除C和C++注释
    一个Windows C++的线程类实现(封装API,形成一个类,但不完善。其实可以学习一下Delphi的TThread的写法)
    协程在Web服务器中的应用(配的图还不错)
    MVC OR API的接口
    Core MVC
    WCF SOAP
    标签辅助类
    构建微服务:Spring boot
  • 原文地址:https://www.cnblogs.com/swm8023/p/2684215.html
Copyright © 2020-2023  润新知