jzoj3348. 【NOI2013模拟】秘密任务

Description

在这里插入图片描述

Input

输入文件为secret.in :
第一行 包含一 个正整数 T,表示有 T组测试数据。接下来 依次是 T组测试数 据。
每组测试数 据的第一行包含两个整N、M。
第二行包含 N - 1个正整数,依次表示 A1,A2, …,AN-1。
接下来 M行,每 行为三个 整数: ui、vi、ci,表示一条连接城市ui和城市 vi的路程等于 ci的高速公路。

Output

输出文件为 secret.out 。
输出 T行, 依次 表示 每组测试数据 的答案 。若最优 方案 唯一 则输出 ”Yes”和 最小 代价 ,否则 输出 ”No ”和最小 代价 。字符串 和整数 之间 请用一个 空格 隔开 。

Sample Input

3
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

【样例解释】
第 1组测试数据: 最优 方案 是在城市 1设立 两个 检查点 。
第 2组测试数据: 最优 方案 是城市 1的高速公路 (1, 4 )的出入口设立 检查点。
第 3组测试数据: 最优 方案 是在城市 2设立 一个 检查点 ,不过 既可以 设置 在 高速公路 (1, 2)的出入 口,也可以 设置 在高速公路 (2, 3)的出入口 。

Data Constraint

对于 10% 的数据: 2 ≤ N ≤ 10 , 1 ≤ M ≤ 20。
另有 40% 的数据: 最优 方案 是唯一 的。
对于 10 0% 的数据: 2 ≤ N ≤ 400, 1 ≤ M ≤ 4 00 0,1 ≤ T ≤ 5,1 ≤ Ai, c ≤ 10^9。无向图可能 有重边 。

题解

我们来发掘发掘题目的条件。
我们发现,frank只能走最短路。
so
我们考虑把最短路图建出来。
怎么建?
先跑一边spfa,求出dis。
然后枚举每一条边,x和y。如果\(dis[x]+边的代价=dis[y]\)则证明这条边是最短路图的边。
跑两边bfs即可。
然后我们发现,每次设立一个检查点就是把一条边给标记成不可通过。
那么这不就是把多条边给割掉使得1与n不连通吗?
最小割!
有因为最小割=最大流
我们在最短路图上跑最大流即可。

问题来了,如何判断只有一种方案呢?
其实这就是一个最小割的唯一性的问题。
有一个很好的解决方案——
我们在残余网络中求出s能够到达的点的集合(容量为0的边不可走)
然后再从t跑一边,记录下t的集合。
如果一条边的两个端点分别是在s集合和t集合中。
则表示当前的边是必割边。
证明显然。
然后如果所有的必割边原来的容量加起来等于最大流,则证明只有一种方案。
证明?
其实一张图即可解决。
在这里插入图片描述
我们发现,上面这种情况中间的两条容量为0的边可以任意割1条。

还要注意:
由于这题的最小割唯一性判断有些奇妙。
因为是一条边的两个端点可以断。
所以把每条边拆成两条边即可。

标程

调到自闭

var
        i,j,k,l,n,m,x,y,z,flow,ll,tot,ans,t,head,tail,took,gs:longint;
        dis,va,a:array[1..4000] of int64;
        map,ttt,da:array[1..3000,1..3000] of int64;
        bz,ss,tt:array[1..4000] of boolean;
        pd,hav:array[1..3000,1..3000] of boolean;
        gap,gapv:array[0..5001] of int64;
        tov,next,last,cap:array[1..100000] of int64;
        flag:boolean;

function min(x,y:longint):longint;
begin
        if x>y then exit(y);exit(x);
end;

procedure insert(x,y,z:longint);
begin
        inc(tot);tov[tot]:=y;next[tot]:=last[x];last[x]:=tot;cap[tot]:=z;
        inc(tot);tov[tot]:=x;next[tot]:=last[y];last[y]:=tot;cap[tot]:=0;
end;

procedure dg(u:longint);
var
        mingap,llt,i,now:longint;
begin
        mingap:=n-1;
        llt:=ll;
        if u=n then
        begin
                inc(flow,ll);
                flag:=true;
                exit;
        end;
        i:=last[u];
        while i>0 do
        begin
                if cap[i]>0 then
                begin
                        if gap[tov[i]]+1=gap[u] then
                        begin
                                if ll>cap[i] then ll:=cap[i];
                                dg(tov[i]);
                                if gap[1]>=n then exit;
                                if flag then
                                begin
                                        now:=i;
                                        break;
                                end;
                                ll:=llt;
                        end;
                        if gap[tov[i]]<mingap then mingap:=gap[tov[i]];
                end;
                i:=next[i];
        end;
        if not flag then
        begin
                dec(gapv[gap[u]]);
                if gapv[gap[u]]=0 then gap[1]:=n;
                gap[u]:=mingap+1;
                inc(gapv[gap[u]]);
        end
        else
        begin
                dec(cap[now],ll);
                inc(cap[now xor 1],ll);
        end;
end;

procedure spfa(dep:longint);
var
        i,j:longint;
begin
        for i:=1 to n do
        begin
                if map[a[dep],i]>0 then
                begin
                        if dis[i]>map[a[dep],i]+dis[a[dep]] then
                        begin
                                dis[i]:=map[a[dep],i]+dis[a[dep]];
                                if bz[i] then
                                begin
                                        bz[i]:=false;
                                        inc(took);
                                        a[took]:=i;
                                end;
                        end;
                end;
        end;
        bz[a[dep]]:=true;
end;
procedure bfs(dep:longint);
var
        i,j:longint;
begin
        for i:=1 to n do
        begin
                if map[a[dep],i]>0 then
                begin
                        if bz[i] then
                        begin
                                bz[i]:=false;
                                inc(took);
                                a[took]:=i;
                        end;
                        if dis[i]=dis[a[dep]]+map[a[dep],i] then
                        begin
                                pd[a[dep],i]:=true;
                        end;
                end;
        end;
end;
procedure find1(dep:longint);
var
        i,j:longint;
begin
        i:=last[a[dep]];
        while i>0 do
        begin
                if bz[tov[i]] then
                begin
                        if cap[i]>0 then
                        begin
                                bz[tov[i]]:=false;
                                ss[tov[i]]:=true;
                                inc(took);
                                a[took]:=tov[i];
                        end;
                end;
                i:=next[i];
        end;
end;
procedure find2(dep:longint);
var
        i,j:longint;
begin
        i:=last[a[dep]];
        while i>0 do
        begin
                if bz[tov[i]] then
                begin
                        if cap[i xor 1]>0 then
                        begin
                                bz[tov[i]]:=false;
                                tt[tov[i]]:=true;
                                inc(took);
                                a[took]:=tov[i];
                        end;
                end;
                i:=next[i];
        end;
end;

begin
        //assign(input,'0data.in');reset(input);
        readln(t);
        while t>0 do
        begin
                dec(t);
                readln(n,m);
                for i:=1 to n-1 do read(va[i]);
                va[n]:=maxlongint;
                fillchar(map,sizeof(map),0);
                fillchar(ttt,sizeof(ttt),0);
                for i:=1 to m do
                begin
                        readln(x,y,z);
                        if (x=4) and (y=6) then
                        j:=j;
                        if map[x,y]>0 then
                        begin
                                if map[x,y]>z then
                                begin
                                        ttt[x,y]:=1;
                                        map[x,y]:=z;
                                end
                                else
                                if map[x,y]=z then inc(ttt[x,y]);
                        end
                        else
                        begin
                                map[x,y]:=z;
                                ttt[x,y]:=1;
                        end;
                        map[y,x]:=map[x,y];
                        ttt[y,x]:=ttt[x,y];
                end;
                head:=1;tail:=1;took:=1;
                fillchar(bz,sizeof(bz),true);
                bz[1]:=false;
                a[1]:=1;
                fillchar(dis,sizeof(dis),127);
                dis[1]:=0;
                repeat
                        for i:=head to tail do spfa(i);
                        head:=tail+1;tail:=took;
                until head>tail;
                fillchar(pd,sizeof(pd),false);
                head:=1;tail:=1;took:=1;
                fillchar(bz,sizeof(bz),true);
                bz[1]:=false;
                a[1]:=1;
                repeat
                        for i:=head to tail do bfs(i);
                        head:=tail+1;tail:=took;
                until head>tail;
                tot:=1;fillchar(last,sizeof(last),0);
                gs:=0;
                k:=0;
                for i:=1 to n-1 do
                        for j:=1 to n do
                                if pd[i,j] then
                                        inc(gs,ttt[i,j]);
                fillchar(da,sizeof(da),0);
                for i:=1 to n-1 do
                        for j:=1 to n do
                                if pd[i,j] then
                                begin
                                        for l:=1 to ttt[i,j] do
                                        begin
                                                inc(k);
                                                hav[i,k+n-1]:=true;
                                                da[i,k+n-1]:=va[i];
                                                insert(i,k+n-1,va[i]);
                                                if j=n then
                                                begin
                                                        da[k+n-1,n+gs]:=va[j];
                                                        insert(k+n-1,n+gs,va[j]);
                                                        hav[k+n-1,n+gs]:=true;
                                                end
                                                else
                                                begin
                                                        da[k+n-1,j]:=va[j];
                                                        insert(k+n-1,j,va[j]);
                                                        hav[k+n-1,j]:=true;
                                                end;
                                        end;
                                end;
                n:=n+gs;
                fillchar(gap,sizeof(gap),0);
                fillchar(gapv,sizeof(gapv),0);
                gapv[0]:=n;
                flow:=0;
                while gap[1]<n do
                begin
                        ll:=maxlongint;
                        flag:=false;
                        dg(1);
                end;
                k:=0;
                head:=1;tail:=1;took:=1;
                fillchar(bz,sizeof(bz),true);
                bz[1]:=false;
                a[1]:=1;
                fillchar(ss,sizeof(ss),false);
                ss[1]:=true;
                repeat
                        for i:=head to tail do find1(i);
                        head:=tail+1;tail:=took;
                until head>tail;
                head:=1;tail:=1;took:=1;
                fillchar(bz,sizeof(bz),true);
                bz[n]:=false;
                a[1]:=n;
                fillchar(tt,sizeof(tt),false);
                tt[n]:=true;
                repeat
                        for i:=head to tail do find2(i);
                        head:=tail+1;tail:=took;
                until head>tail;
                for i:=1 to n do
                begin
                        for j:=1 to n do
                        begin
                                if hav[i,j] then
                                begin
                                        if (ss[i]) and (tt[j]) then
                                        begin
                                                inc(k,da[i,j]);
                                        end;
                                end;
                        end;
                end;
                if k<>flow then write('No ') else write('Yes ');
                writeln(flow);
        end;
end.
end.



posted @ 2019-07-10 20:39  RainbowCrown  阅读(184)  评论(0编辑  收藏  举报