Gym - 101208C 2013 ACM-ICPC World Finals C.Surely You Congest 最大流+最短路

题面

题意:给你n(2w5)个点,m条边(7w5)有k(1e3)辆车停在某些点上的,然后他们都想尽快去1号点,同时出发,同一个点不允许同时经过,

        如果多辆车同时到达一个点,他们就会堵塞,这时候只能选择通过一辆车,其他车相当于就地爆炸

        问最后能有多少车到1号点

题解:想象如果2辆车的最短路不相交,那么他们就互相之间没有了影响,再想象对于一般的图,如何控制度数的,显然有一个网络流的做法

        可以走的边就连,度数为1,现在我们考虑每部分最短路长度相等的点集才会受到影响.如果2个点到1的最短路长度一样,那么他们才

        可能会经过同一个点,于是针对每一堆最短路一样的,单独建图,累加他们的和就是答案.

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define lld long long 
  4 using namespace std;
  5 #define N 30007
  6 #define M 100007
  7 #define inf 100000000000000LL
  8 namespace Dinic
  9 {
 10     int head[N],head2[N],p=1;
 11     struct Rec
 12     {
 13         int go,nex;
 14         lld c;
 15     }eg[M*2],e[M*2];
 16     void build(int a,int b,lld c)
 17     {
 18         //printf("%d %d %d\n",a,b,c);
 19         eg[++p]=(Rec){b,head[a],-c};
 20         head[a]=p;
 21         eg[++p]=(Rec){a,head[b],0};
 22         head[b]=p;
 23     }
 24     lld dis[N],ans;
 25     int Q[N],s[N],S,T,stop;
 26     bool bfs()
 27     {
 28         memset(dis,0,sizeof(dis));
 29         dis[T]=1;
 30         Q[1]=T;
 31         for (int p1=1,p2=1;p1<=p2;p1++)
 32         {
 33             for (int i=head[Q[p1]];i;i=eg[i].nex)
 34                 if (eg[i^1].c<0&&!dis[eg[i].go])
 35                 {
 36                     dis[eg[i].go]=dis[Q[p1]]+1;
 37                     Q[++p2]=eg[i].go;
 38                 }
 39         }
 40         if (!dis[S]) return false;
 41         memcpy(head2,head,sizeof(head));
 42         return true;
 43     }
 44     bool dinic(int p,int top)
 45     {
 46         if (p==T)
 47         {
 48             lld x=inf;
 49             for (int i=1;i<=top-1;i++) if (-eg[s[i]].c<x) x=-eg[s[i]].c,stop=i;
 50             for (int i=1;i<=top-1;i++) eg[s[i]].c+=x,eg[s[i]^1].c-=x;
 51             ans+=x;
 52             return true;
 53         }
 54         for (int &i=head2[p];i;i=eg[i].nex)
 55         {
 56             if (eg[i].c<0&&dis[eg[i].go]==dis[p]-1)
 57             {
 58                 s[top]=i;
 59                 if (dinic(eg[i].go,top+1)&&top!=stop) return true;
 60             }
 61         }
 62         return false;
 63     }
 64     lld ask()
 65     {
 66         ans=0;
 67         while (bfs()) dinic(S,1);
 68         return ans; 
 69     }
 70     void init(int _S,int _T){
 71         S=_S,T=_T;
 72     }
 73 }
 74 using namespace Dinic;
 75 void clear()
 76 {
 77     p=1;
 78     memset(head,0,sizeof(head));
 79 }
 80 int n,m,ss,tt,why=0;
 81 long long diss[N];
 82 void addedge(int a,int b,lld c)
 83 {
 84     p++;
 85     e[p].go=b;
 86     e[p].c=c;
 87     e[p].nex=head[a];
 88     head[a]=p;
 89 }
 90 void dijkstra()
 91 {
 92     priority_queue<pa,vector<pa>,greater<pa> >q;
 93     for (int i=1;i<=n;i++) diss[i]=inf;
 94     diss[1]=0;
 95     q.push(make_pair(0,1));
 96     while (!q.empty())
 97     {
 98         int now=q.top().second;
 99         q.pop();
100         for (int i=head[now];i;i=e[i].nex)
101             if(diss[now]+e[i].c<diss[e[i].go])
102             {
103                 diss[e[i].go]=diss[now]+e[i].c;
104                 q.push(make_pair(diss[e[i].go],e[i].go));
105             }
106     }
107 }
108 int u[M],v[M],w[M],pos[M],c;
109 void solve(int l, int r) 
110 {
111     clear();
112     ss=n+1;
113     tt=n+2;
114     init(ss,tt);
115     for(int i = 1; i <= m; i++) build(u[i], v[i], 1);
116     for(int i = l; i <= r; i++) build(pos[i], tt, 1);
117     build(ss, 1, r - l + 1);
118     why += ask();
119     //cout << ans <<endl;
120 }
121 bool cmp_(int a, int b) {
122     return diss[a] < diss[b];
123 }
124 int main()
125 {
126     scanf("%d%d%d", &n, &m, &c);
127     p=0;
128     for(int i = 1; i <= m; i++) scanf("%d%d%d", &u[i], &v[i], &w[i]);
129     for(int i = 1; i <= c; i++) scanf("%d", &pos[i]);
130     for(int i = 1; i <= m; i++) addedge(u[i], v[i], w[i]), addedge(v[i], u[i], w[i]);
131     dijkstra();
132     //for (int i=1;i<=n;i++) printf("%d\n",diss[i]);
133     int tmp = 0;
134     for(int i = 1; i <= m; i++) {
135         if(diss[u[i]] > diss[v[i]]) swap(u[i], v[i]);
136         if(diss[v[i]] == diss[u[i]] + w[i]) {
137             ++tmp;
138             swap(u[i], u[tmp]);
139             swap(v[i], v[tmp]);
140             swap(w[i], w[tmp]);
141         }
142     }
143     m = tmp;
144     sort(pos + 1, pos + c + 1, cmp_);
145     for(int i = 1, j; i <= c; i = j) {
146         j = i;
147         while(diss[pos[i]] == diss[pos[j]] && j <= c) j++;
148         if (diss[pos[i]]==inf) break;
149         solve(i, j - 1);
150         //cout << i << " " << j  - 1 <<endl;
151     }
152     printf("%d", why);
153     return 0;
154 }

 

转载于:https://www.cnblogs.com/qywhy/p/10592198.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值