{题解}[jzoj1729]blockenemy

来源:互联网 发布:乐乎网络电话 编辑:程序博客网 时间:2024/06/09 20:53

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
原创粉丝点击