bzoj 3258: 秘密任务
来源:互联网 发布:阿里云发票信息修改 编辑:程序博客网 时间:2024/05/24 04:34
Description
Alice听说在一片神奇的大陆MagicLand,有一个古老的传说……
很久很久以前,那个时候 MagicStates共和国刚刚成立。 反对新政府的势力虽已被镇压,但仍然在暗地活动。这一次,情报局得到了一个令人震惊的消息,被软禁在首都府邸中的Frank ——著名的反对派领袖,秘密逃出首都,去往反对派的大本营。根据相关的情报,Frank计划通过城市之间 发达的高速公路,经过最短的路程抵达目的地。不妨将 MagicStates共和国简化为由N个城市,M条高速公路构成的连通的无向图,首都为城市1,反对派的大本营为城市N。
每条高速公路连接两个不同的城市,且路程是已知的。而Frank选择了一条从城市1到城市N的最短路径作为他的逃跑路线。为了阻止Frank,共和国总统决定在某些城市的高速公路的出入口设立检查 点,在Frank经过检查点时将他逮捕。
举例来说,如果有一条高速公路连接城市u和城市v,在这条公路的城市u或城市v的出入口设立检查点,那么Frank经过高速公路时就会被发现。特别的是,由于城市N实际上处在反对派的控制下,所以不能在城市N设立检查点。
然而在任何城市设立检查点都需要一定的费用。更具体的,若在城市 u设立k个检查点,就要花费 Au乘以k的代价,其中Au是城市u的相关参数。值得注意的是,这个代价与这k个检查点具体设在哪些公路的出入口无关,于是,总统责令情报局拟定一个方案,花费最小的代价使得无论Frank选择哪条最短路线,都会在(除城市N以外)某个城市的高速公路出入口被发现。读到这里,Alice很想知道阻止Frank所需要花费的最小代价,并且她还希 望知道最优方案是否是唯一的。只好再请你帮助她了。
注意,我们称两个方案不同当且仅当存在某城市k,两种方案中在城市 k的检查点的设置(而不仅是数目)是不同的。
注意,输入文件包含多组测试数据。
Input
第一行包含一个正整数T,表示有T组测试数据。接下来依次是T组测试数据。
每组测试数据的第一行包含两个整数 N、M。
第二行包含N - 1个正整数,依次表示A1,A2, …,An-1。
接下来M行,每行三个整数Ui,Vi,Ci,表示一条连接城市Ui和城市Vi的路程等于Ci的高速公路
Output
输出T行,依次表示每组测试数据的答案。若最优方案唯一则输出 ”Yes” 和
最小代价,否则输出”No”和最小代价。字符串和整数之间请用一个空格隔开。
Sample Input
3 3
2 4
1 3 23
3 2 12
2 1 11
4 4
3 2 2
1 2 1
2 3 1
3 4 1
4 1 1
3 4
3 2
1 2 1
2 3 2
2 3 19
3 1 4
Sample Output
Yes 4
Yes 3
No 2
HINT
第1组测试数据:最优方案是在城市1 设立两个检查点。
第2组测试数据:最优方案是城市1的高速公路( 1, 4)的出入口设立检查点。
第3组测试数据:最优方案是在城市2设立一个检查点,不过既可以设置在
高速公路(1, 2)的出入口,也可以设置在高速公路(2, 3)的出入口。
对于100%的数据:2 ≤ N ≤ 400 , 1≤ M ≤ 4 000 ,1 ≤ T ≤ 5 ,
1 ≤ Ai, c ≤ 10^9。无向图可能有重边。
最短路图+求最小割+判断最小割是否唯一
最短路图可以用spfa求。然后最小割
然后判断最小割是否唯一的时候。网上有个bfs的方法=-=不过我偷了个懒所以贴了个tarjan模板上去
tarjan缩点之后。判断是否所有不在一个联通块的满流边都是S所在联通块指向T所在。是的话唯一。不是的话不唯一
= =Yes和No写成了YES和NO
记得spfa的dis要开longlong
记得如果最小割中的边两个端点权值相同则不为已
都是坑!
#include<queue>#include<cstdio>#include<string>#include<cstring>using namespace std;inline int min(int x,int y){ if(x<y) return x; return y;}int head[100001],exhead[100001];struct map{ long long f; int s,t; int next;}a[400001],exa[400001];int edge,exedge;int p;int q[400001],d[400001];int haedge[400001];inline void add1(int s,int t,int f,int xxx){ a[edge].next=head[s]; head[s]=edge; a[edge].s=s; a[edge].t=t; a[edge].f=f; haedge[xxx]=edge;}inline void add(int s,int t,long long f){ a[edge].next=head[s]; head[s]=edge; a[edge].s=s; a[edge].t=t; a[edge].f=f;}inline void exadd(int s,int t,long long f){ exa[exedge].next=exhead[s]; exhead[s]=exedge; exa[exedge].s=s; exa[exedge].t=t; exa[exedge].f=f;}inline bool bfs(){ int l=0,r=0; memset(q,0,sizeof(q)); r++; q[r]=1; memset(d,-1,sizeof(d)); d[1]=0; int i,k; while(l<r) { l++; int k=q[l]; for(i=head[k];i!=0;i=a[i].next) { if(a[i].f>0&&d[a[i].t]==-1) { d[a[i].t]=d[k]+1; r++; q[r]=a[i].t; } } } if(d[p]>=0) return true; return false;}inline int dfs(int k,int s){ if(k==p) return s; int t=s; int i; for(i=head[k];i!=0;i=a[i].next) { if(d[a[i].t]==d[k]+1&&a[i].f>0) { int xx=dfs(a[i].t,min(s,a[i].f)); a[i].f-=xx; if(i%2==0) a[i-1].f+=xx; else a[i+1].f+=xx; s-=xx; } } return t-s;}inline int maxflow(){ int s=0; while(bfs()) s+=dfs(1,2100000000); return s;}long long dis[401];bool v[401];inline void spfa(){ int i; for(i=1;i<=400;i++) dis[i]=(long long)1000000000*(long long)4000; memset(v,false,sizeof(v)); queue <int>Q; while(!Q.empty()) Q.pop(); Q.push(1); dis[1]=0; v[1]=true; while(!Q.empty()) { int d=Q.front(); v[d]=false; Q.pop(); int i; for(i=exhead[d];i!=0;i=exa[i].next) { int t=exa[i].t; if(dis[d]+exa[i].f<dis[t]) { dis[t]=dis[d]+exa[i].f; if(!v[t]) { Q.push(t); v[t]=true; } } } }}int scc,cnt;int s[10001],top;int dfn[10001],low[10001],belong[10001];inline void tarjan(int d){ int i,x; cnt++; dfn[d]=cnt; low[d]=cnt; top++; s[top]=d; v[d]=true; for(i=head[d];i!=0;i=a[i].next) { if(a[i].f==0) continue; x=a[i].t; if(dfn[x]==0) { tarjan(x); low[d]=min(low[d],low[x]); } else if(v[x]&&low[d]>dfn[x])//v在栈中,修改low[u] low[d]=dfn[x]; } if(dfn[d]==low[d])//u为该强连通分量中遍历所成树的根 { scc++; x=s[top]; top--; while(x!=d) { v[x]=false; belong[x]=scc; x=s[top]; top--; } v[x]=false; belong[x]=scc; }}int dk[4001];struct cc{ int ss,tt,x;}ed[1000001];int main(){ int T; scanf("%d",&T); while(T>0) { T--; memset(head,0,sizeof(head)); memset(a,0,sizeof(a)); memset(exhead,0,sizeof(exhead)); memset(exa,0,sizeof(exa)); memset(haedge,0,sizeof(haedge)); edge=0; exedge=0; int n,m; scanf("%d%d",&n,&m); int i; for(i=1;i<=n-1;i++) scanf("%d",&dk[i]); dk[n]=2100000000; int s,t,x; for(i=1;i<=m;i++) { scanf("%d%d%d",&s,&t,&x); exedge++; exadd(s,t,x); exedge++; exadd(t,s,x); } spfa(); int pp=0; for(i=1;i<=exedge;i++) { if(dis[exa[i].s]+exa[i].f==dis[exa[i].t]) { x=dk[exa[i].s]; x=min(x,dk[exa[i].t]);pp++; ed[pp].ss=exa[i].s;ed[pp].tt=exa[i].t;ed[pp].x=x; edge++; add1(ed[pp].ss,ed[pp].tt,ed[pp].x,pp); edge++; add(ed[pp].tt,ed[pp].ss,0); } } p=n; int ans=maxflow(); memset(v,false,sizeof(v)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(belong,0,sizeof(belong)); top=0; for(i=1;i<=n;i++) if(dfn[i]==0) tarjan(i); int flag=-1; for(i=1;i<=pp;i++) { if(a[haedge[i]].f==0) { if(belong[ed[i].ss]==belong[1]&&belong[ed[i].tt]!=belong[n]&&belong[ed[i].tt]!=belong[1]||dk[ed[i].ss]==dk[ed[i].tt]) { flag=0; break; } } } if(flag==-1) printf("Yes "); else printf("No "); printf("%d\n",ans); } return 0;}
- bzoj 3258: 秘密任务
- [最小割唯一性 Tarjan 最短路图] BZOJ 3258 秘密任务
- BZOJ 1556 墓地秘密
- BZOJ 1556: 墓地秘密【状压DP
- 【NOI(P)2013模拟】秘密任务
- bzoj3258: 秘密任务 (+一百题感言?)
- BZOJ 2336: [HNOI2011]任务调度
- BZOJ 2726 SDOI 任务安排
- BZOJ 2726 [SDOI2012]任务安排
- 【BZOJ 2336】任务调度 【随机化】
- BZOJ 3932任务查询系统
- bzoj 2726: [SDOI2012]任务安排
- bzoj 2726: [SDOI2012]任务安排
- 【BZOJ】1590: [Usaco2008 Dec]Secret Message 秘密信息
- BZOJ 1590: [Usaco2008 Dec]Secret Message 秘密信息 Trie树
- bzoj 1590 luogu2292 [USACO08DEC]秘密消息Secret Message(题解)
- 《秘密》
- 秘密
- The new day of my blog
- java实现同步map的几种方法(lock,synchronized,rwlock,ConcurrentHashMap,hashtable,SynchronizedMap)
- 手机音量键控制SoundPool大小
- 汽车加油问题
- 加快网站访问速度的9大方法
- bzoj 3258: 秘密任务
- 函数指针
- 检查网络是否畅通的四个步骤
- arm linux 启动之三:kernle_init
- 设置Qt应用程序图标
- Qt for ios开发:软件发布真机测试出现闪退
- 「泡」改变泡型 20140920 ④微我控制
- 黑马程序员_交通灯管理系统
- 读了这么多年书,终于拿到人生中第一个offer