zoukankan      html  css  js  c++  java
  • 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.
    
    
    
    
  • 相关阅读:
    最小生成树Prim算法
    哈夫曼树与哈夫曼编码
    二叉树的非递归遍历
    浅谈C++中指针和引用的区别
    poj2406 Power Strings
    (收藏)KMP算法的前缀next数组最通俗的解释
    HDU 1556 Color the ball
    Floyd算法
    最短路Dijkstra和Flyod
    编程中无穷大常量的设定技巧
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11166339.html
Copyright © 2011-2022 走看看