NOIP模拟赛花园的守护之神(greendam)-最短路-最大流最小割

Posted SkyLYnf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP模拟赛花园的守护之神(greendam)-最短路-最大流最小割相关的知识,希望对你有一定的参考价值。

Problem Greemdam

题目大意

给一个图$G=(V,E)$,求要使这个图的最短路增长所需要增加的最小权值的值。

Solution

既然是要求这个玩意儿,我们可以排除除了最短路以外的所有路径,因为这些是无用的。

对于每一条最短路路径,如果这条路径与任意一个最短路路径有相同的一条边,

那我们只需要在这条边权值加一就可以保证这两个最短路都增加了。

所以我们转化为求不相交边的最短路路径数,

其实就是这个图的最小割。

我们给最短路的图每个边附权值为1(因为前权值是无用的),

跑一遍最大流即可。

Dijkstra跑的要比spfa快。最好加个优先队列优化。

Datamaker

首先声明这个datamaker是无用的,最多只能让你看看极限数据跑多久。

因为随机出来数据所有的答案都是1。

 1 #include <iostream>
 2 #include <ctime>
 3 #include <cstdio>
 4 #define MAXN 1000
 5 #define MAXM 500000
 6 #define MAXC 1000000
 7 using namespace std;
 8 int main(){
 9     freopen("b.in","w",stdout);
10     srand(time(NULL));
11     int st=rand()%(MAXN-1)+1,ed=rand()%(MAXN-1)+1;
12     while(st==ed)ed=rand()%(MAXN-1)+1;
13     printf("%d %d %d %d\n",MAXN,MAXM,st,ed);
14     for(int i=1;i<=MAXM;i++)
15         printf("%d %d %d\n",rand()%(MAXN-1)+1,rand()%(MAXN-1)+1,rand()%(MAXC-1)+1);
16 }

AC Code

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <queue>
 6 #define INF 1e15
 7 #define ll long long
 8 using namespace std;
 9 struct node{
10     int to,next,from;
11     ll w;
12 }e[1000010];
13 struct nodee{
14     int to,next,w;
15 }a[1000010];
16 typedef pair<int,int> pa;
17 int n,m,st,ed,u,v,ans=0,tot=0,tott=1;
18 int h[1010],hh[1010],dis[1010],q[1010];
19 ll w,d[1010];
20 bool visit[1010];
21 void add(int u,int v,ll w){
22     e[++tot].to=v;e[tot].next=h[u];
23     h[u]=tot;e[tot].w=w;e[tot].from=u;
24     e[++tot].to=u;e[tot].next=h[v];
25     h[v]=tot;e[tot].w=w;e[tot].from=v;
26 }
27 void insr(int u,int v,int w){
28     a[++tott].to=v;a[tott].next=hh[u];
29     hh[u]=tott;a[tott].w=w;
30     a[++tott].to=u;a[tott].next=hh[v];
31     hh[v]=tott;a[tott].w=0;
32 }
33 bool bfs(){
34     int head=0,tail=1;
35     memset(dis,-1,sizeof(dis));
36     dis[st]=0;q[0]=st;
37     while(head!=tail){
38         int now=q[head];
39         for(int i=hh[now];~i;i=a[i].next)
40             if(a[i].w&&dis[a[i].to]==-1){
41                 dis[a[i].to]=dis[now]+1;
42                 q[tail++]=a[i].to;
43             }
44         head++;
45     }
46     return dis[ed]!=-1;
47 }
48 int dfs(int now,int flow){
49     if(now==ed)return flow;
50     int w,used=0;
51     for(int i=hh[now];~i;i=a[i].next)
52         if(dis[now]+1==dis[a[i].to]){
53             w=dfs(a[i].to,min(a[i].w,flow-used));
54             a[i].w-=w;
55             a[i^1].w+=w;
56             used+=w;
57             if(used==flow)return flow;
58         }
59     if(!used)dis[now]=-1;
60     return used;
61 }
62 void dijkstra(){
63     memset(visit,0,sizeof(visit));
64     for(int i=1;i<=n;i++)d[i]=INF;
65     d[st]=0;
66     priority_queue<pa,vector<pa>,greater<pa>> q;
67     q.push(make_pair(0,st));
68     while(!q.empty()){
69         int now=q.top().second;
70         q.pop();
71         if(!visit[now]){
72             visit[now]=1;
73             for(int i=h[now];~i;i=e[i].next)
74                 if(d[now]+e[i].w<d[e[i].to]){
75                     d[e[i].to]=d[now]+e[i].w;
76                     q.push(make_pair(d[e[i].to],e[i].to));
77                 }
78         }
79     }
80 }
81 int main(){
82     //freopen("b.in","r",stdin);
83     //freopen("b.out","w",stdout);
84     memset(h,-1,sizeof(h));
85     memset(hh,-1,sizeof(hh));
86     scanf("%d%d%d%d",&n,&m,&st,&ed);
87     for(int i=1;i<=m;i++){
88         scanf("%d%d%lld",&u,&v,&w);
89         add(u,v,w);
90     }
91     dijkstra();
92     for(int i=1;i<=tot;i++)
93         if(d[e[i].from]+e[i].w==d[e[i].to])
94             insr(e[i].from,e[i].to,1);
95     while(bfs())
96         ans+=dfs(st,1e9);
97     printf("%d",ans);
98 }

 

以上是关于NOIP模拟赛花园的守护之神(greendam)-最短路-最大流最小割的主要内容,如果未能解决你的问题,请参考以下文章

[OI - 模拟考] LYOI2018模拟考N

12星座守护神是啥?

2017.5.27 NOIP模拟赛(hzwer2014-5-16 NOIP模拟赛)

2017.12.09NOIP提高组模拟赛A组

2017.11.25NOIP提高组模拟赛A组

NOIP提高组模拟赛13