您的位置:首页 > 其它

【POJ 2531】Network Saboteur

2015-08-10 11:15 351 查看
【POJ 2531】Network Saboteur

图的搜索 剪枝真是门学问。。剪好了快的可真不是一倍两倍

刚开始搜的思路有问题 TLE了 后来枚举点暴力搜了一发 两百多ms

由于查找时权值是不断增加的 所以直接找集合间最大权的话不方便设置return点

看disscuss发现有一大牛 建了两个数组 通过所有边权-两集合内部边权(去重) 得到答案 dfs的时候找最小内部边权即可 当前状态权值>当前最小内部边权时直接跳出 两个数组分别寸当前状态两个集合中所含的点 每加一个点分别往两边加 假设要将点u加入A集合 那么内部权值就要加上u与A中现存的所有点的边权 最后用所有边权-两集合最小内部边权就是最大集合间边权

代码如下:

//渣剪枝
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

bool vis[21];
int mp[21][21];
int n,mx;

void dfs(int id,int flow)
{
    mx = max(mx,flow);
    vis[id] = 1;
    int i;
    for(i = 1; i <= n; ++i)
    {
        if(vis[i]) flow -= mp[id][i];
        else flow += mp[id][i];
    }

    for(i = id+1; i <= n; ++i)
    {
        dfs(i,flow);
        vis[i] = 0;
    }
}

int main()
{
    int i,j;
    scanf("%d",&n);
    mx = 0;
    memset(mp,0,sizeof(mp));
    for(i = 1; i <= n; ++i)
    {
        for(j = 1; j <= n; ++j) scanf("%d",&mp[i][j]);
    }
    dfs(0,0);
    printf("%d\n",mx);
    return 0;
}


//大牛剪枝
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

int l[21],r[21];//左右集合
int mp[21][21];
int n,cut;//cut--内部边权

void dfs(int k,int flow,int in,int out)
{
    if(flow >= cut) return;//当前集合内边权已比最小集合内边权大 return
    int i,j,s;

    s = 0;
    for(i = 1; i <= in; ++i)//当前点与左集合各点边权
    {
        s += mp[k][l[i]];
    }
    if(k == n)
    {
        cut = min(cut,flow+s);
    }
    else
    {
        l[in+1] = k;
        dfs(k+1,flow+s,in+1,out);
    }

    s = 0;
    for(i = 1; i <= out; ++i)//当前点与右集合各点边权
    {
        s += mp[k][r[i]];
    }
    if(k == n)
    {
        cut = min(cut,flow+s);
    }
    else
    {
        r[out+1] = k;
        dfs(k+1,flow+s,in,out+1);
    }
}

int main()
{
    int i,j,sum = 0;
    scanf("%d",&n);
    for(i = 1; i <= n; ++i)
    {
        for(j = 1; j <= n; ++j)
        {
            scanf("%d",&mp[i][j]);
            sum += mp[i][j];
        }
    }

    sum /= 2;//两两点间边权(去重)
    cut = INF;//初始集合内边权最大

    l[1] = 1;
    dfs(2,0,1,0);
    printf("%d\n",sum-cut);
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: