{题解}[jzoj1729]blockenemy

jzoj1729

Description

你在玩电子游戏的时候遇到了麻烦。。。。。。 你玩的游戏是在一个虚拟的城市里进行,这个城市里有n个点,都从0~n-1编了号,每两个点之间有且仅有一条路径。现在,你的敌人到这个城市来踩点了!!!为了阻止他们更好的踩点, 你决定切断他们所有踩点人员的联系,使他们孤军作战,然后在各个击破。但是这就要切断某些街道,而你每切断一条路,市民就会产生相对的不满值,不满值越大,城市的和谐度就越小。所以你现在需要知道为了使踩点人员所在的点两两之间不联通所切断的边产生的最小不满值是多少?

额,使树上m个点不联通的最小代价?就这么理解罢。

Idea

着实吓人,但事实上也不怎么可怕。
不多讨论部分分了,直接考虑100%的数据
有两种不错的方法。

Ⅰ树形DP

f[x]x
g[x]
由于这个方法没有成功融会贯通,所以只好贴别人的。
这里写图片描述
不过我并不推荐树形DP
确乎有些小题大做
不会Ⅱ贪心(+并查集)
没有关系,我们还有法Ⅲ

Ⅲ贪心+LCA

这是由Couzit黄靖元提供的方法。
显然,这是一棵树,所以任意两点的路径唯一的。
我们考虑 x,y
为使 x,y ,我们最少需要删去路径上一条边。
若不考虑其他的点,我们必定是选择边权最小的边删去,显然的局部最优
稍加思索,我们发现对于整个图(全局),这也是最优的
因此,我们只需枚举相连通的两点,删去路径上最短边即可。
可以用 O(n2) 解决。

很蹊跷,不是吗?
有没有可能
我们可以尝试举一个反例。
红色点为踩点人员所在点
反例呵呵
如果我们删去权值为3的边,是不是更优呢?然而并不是的。
不要为你的双眼所蒙蔽,如果我们删去权值为3的边,左子树的两点是联通的!

意会意会,这种贪心策略正确性是保证的。
最重要的,这种方式码量极少!

Code

法Ⅰ
const   maxn=500;
var     i,n,x,y,l,tot:longint;
        yy,next,cost,g,fa,f,gu:array[1..maxn] of longint;
        t:array[1..maxn] of boolean;
function max(x,y:longint):longint; begin if x>y then exit(x);exit(y);end;
function min(x,y:longint):longint; begin if x>y then exit(y);exit(x);end;
procedure make(x,y,l:longint);
begin
        inc(tot);
        yy[tot]:=y;
        next[tot]:=gu[x];
        cost[tot]:=l;
        gu[x]:=tot;
end;
procedure dfs(x:longint);
var     i,j,sum,y:longint;
begin
        i:=gu[x];
        sum:=0;
        while i<>0 do begin
                y:=yy[i];
                if fa[x]<>y then begin
                        fa[y]:=x;
                        dfs(y);
                        if t[y] then begin
                                f[x]:=f[x]+f[y]+cost[i];
                                g[x]:=g[x]+f[y]+cost[i];
                                sum:=max(sum,cost[i]);
                        end else begin
                                f[x]:=f[x]+min(g[y]+cost[i],f[y]);
                                if g[y]+cost[i]>f[y] then begin
                                        sum:=max(sum,f[y]-g[y]);
                                        g[x]:=g[x]+f[y];
                                end else begin
                                        sum:=max(sum,cost[i]);
                                        g[x]:=g[x]+g[y]+cost[i];
                                end;
                        end;
                end;
                i:=next[i];
        end;
        if t[x] then g[x]:=f[x] else g[x]:=g[x]-sum;
end;
begin
        readln(n);
        for i:=1 to n-1 do begin
                readln(x,y,l);
                make(x+1,y+1,l);
                make(y+1,x+1,l);
        end;
        while not eof do begin
                readln(x);
                t[x+1]:=true;
        end;
        dfs(1);
        writeln(min(f[1],g[1]));
end.
法Ⅱ
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

const int N = 55;
int n,ans;
int h[N],flag[N];
struct node
{
    int x,y,z;
} a[N];

bool cmp(node A,node B)
{return A.z>B.z;}

int gf(int x)
{
    if (x!=h[x]) h[x] = gf(h[x]);
    return h[x];
}


bool link(int x,int y)
{
    int i = gf(x),j = gf(y);
    if (flag[i] && flag[j]) return 0;
    else 
    {
        h[i] = j;
        flag[j] |= flag[i];
    }
    return 1;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i ++) 
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    int x;
    while (scanf("%d",&x)!=EOF) flag[x] = 1;
    for (int i=1;i<=n;i ++) h[i] = i;

    sort(a+1,a+n,cmp);
    for (int i=1;i<n;i ++)
        if (!link(a[i].x,a[i].y)) 
            ans += a[i].z;
    printf("%d\n",ans);
    return 0;
}
法Ⅲ
const
        maxn=50;
        maxm=50;
var
        n,tot:longint;
        i,j,l:longint;
        fx,fy:longint;
        ans,min:longint;
        numx,numy:longint;
        bz:array[0..maxn] of boolean;
        fa,q,dep:array[0..maxn] of longint;
        a,map:array[0..maxn,0..maxn] of longint;
procedure dfs(x,deep:longint);
var
        i:longint;
begin
        if(bz[x])then exit;
        bz[x]:=true;dep[x]:=deep;
        for i:=1 to a[x][0] do
        if(not bz[a[x][i]])then
        begin
                fa[a[x][i]]:=x;
                dfs(a[x][i],deep+1);
        end;
end;
procedure init;
var
        i,j:longint;
        x,y,c:longint;
begin
        fillchar(map,sizeof(map),$7f);
        readln(n);
        for i:=1 to n-1 do
        begin
                readln(x,y,c);
                inc(a[x][0]);a[x][a[x][0]]:=y;
                inc(a[y][0]);a[y][a[y][0]]:=x;
                map[x][y]:=c;map[y][x]:=c;
        end;
        fa[0]:=0;
        while(not seekeof)do
        begin
                inc(tot);
                readln(q[tot]);
        end;
end;
procedure swap(var a,b:longint);
var
        c:longint;
begin
        c:=a;a:=b;b:=c;
end;
begin
        init();
        dfs(0,1);
        for i:=1 to tot-1 do
        begin
                for j:=i+1 to tot do
                begin
                        min:=maxlongint;
                        fx:=q[i];fy:=q[j];
                        if(dep[fx]<dep[fy])then swap(fx,fy);
                        while(dep[fx]>dep[fy])do
                        begin
                                if(map[fx,fa[fx]]<min)then
                                begin
                                        min:=map[fx,fa[fx]];
                                        numx:=fx;
                                        numy:=fa[fx];
                                end;
                                fx:=fa[fx];
                        end;
                        while(fx<>fy)do
                        begin
                                if(map[fx,fa[fx]]<min)then
                                begin
                                        min:=map[fx,fa[fx]];
                                        numx:=fx;
                                        numy:=fa[fx];
                                end;
                                if(map[fy,fa[fy]]<min)then
                                begin
                                        min:=map[fy,fa[fy]];
                                        numx:=fy;
                                        numy:=fa[fy];
                                end;
                                fx:=fa[fx];fy:=fa[fy];
                        end;
                        inc(ans,min);
                        map[numx,numy]:=0;map[numy,numx]:=0;
                end;
        end;
        writeln(ans);
        close(input);close(output);
end.
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值