HDU 5483 Nux Walpurgis 图的最小生成树中必要的边的数目 动态MST问题

来源:互联网 发布:剑网3天策超帅捏脸数据 编辑:程序博客网 时间:2024/06/08 06:09

裸的动态MST

两次dp就可以辣

#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>using namespace std;#define scan(x) scanf("%d",&(x))#define scan2(x,y) scanf("%d%d",&(x),&(y))#define scan3(x,y,z) scanf("%d%d%d",&(x),&(y),&(z))#define scan4(x,y,z,k) scanf("%d%d%d%d",&(x),&(y),&(z),&(k))const int maxn = 3003;const int maxm = maxn * maxn;const int inf = 1000000000;int n, m;__int64 mst;int map[maxn][maxn];int dp[maxn][maxn], best[maxn][maxn];int dis[maxn], pre[maxn];bool vis[maxn];vector<int> edge[maxn];#include<iostream>int minz(int a, int b){    return a < b ? a : b;}void init(){    int i, j;    for(i = 0; i < n; i++)    {        for(j = 0; j < n; j++)            map[i][j] = dp[i][j] = inf;        edge[i].clear();        vis[i] = 0;        pre[i] = -1;        dis[i] = inf;    }}void input(){//cerr<<"st"<<endl;//    int x, y, z;//    while(m--)//    {//        scanf("%d%d%d", &x, &y, &z);//        cerr<<x<<" "<<y<<" "<<z<<endl;//        map[x][y] = map[y][x] = z;//    }        for(int i=0;i<n;i++){                for(int j=i+1;j<n;j++){                        int w;scan(w);                        map[i][j] = map[j][i] = w;                        //cerr<<i<<" "<<j<<" "<<w<<endl;                }        }}void prim(){    int i, j, k;    for(i = 1; i < n; i++)    {        dis[i] = map[0][i];        pre[i] = 0;    }    dis[0] = inf;    vis[0] = 1;    pre[0] = -1;    mst = 0;    for(i = 0; i < n-1; i++)    {        k = 0;        for(j = 1; j < n; j++)            if(!vis[j] && dis[k] > dis[j])                k = j;        vis[k] = 1;        mst += dis[k];       //建最小生成树        if(pre[k] != -1)            edge[k].push_back(pre[k]),            edge[pre[k]].push_back(k);        for(j = 1; j < n; j++)            if(!vis[j] && dis[j] > map[k][j] )                dis[j] = map[k][j], pre[j] = k;    }}int dfs1(int u, int fa, int rt) // 求 点rt 到 以u为根的数及其子树的最小距离{    int i;    for(i = 0; i < edge[u].size(); i++)    {        int v = edge[u][i];        if(v == fa) continue;        dp[rt][u] = minz(dp[rt][u], dfs1(v, u, rt));    }    if(fa != rt) dp[rt][u] = minz(dp[rt][u], map[rt][u]);    return dp[rt][u];}int dfs2(int u, int fa, int rt) // 求 以rt为根的数及其子树 到 以u为根的数及其子树的最小距离{    int i;    int ans = dp[u][rt];    for(i = 0; i < edge[u].size(); i++)    {        int v = edge[u][i];        if(v == fa) continue;        ans = minz(ans, dfs2(v, u, rt));    }    return ans;}void solve(){    int i,j;    for(i = 0; i < n; i++)        dfs1(i, -1, i);    for(i = 0; i < n; i++)        for(j = 0; j < edge[i].size(); j++)        {            int v = edge[i][j];            best[i][v] = best[v][i] = dfs2(v, i, i);        }}void query(){//    int x, y, z;//    double sum = 0;//    scanf("%d", &m);//    x=1,y=3,z=10;//        if(pre[x] != y && pre[y] != x)//            sum += mst * 1.0;//        else//            sum += mst * 1.0 - map[x][y] + minz(best[x][y], z);//    printf("%.4f\n", sum/1);    int ans =0 ;    for(int i=0;i<n;i++){        int x=i;        for(int j=0;j<edge[i].size() ; j++){                int y=edge[i][j];                if(x<y) continue;                int sum = mst - map[x][y] + best[x][y];                //cerr<<"best:"<<best[x][y]<<endl;                if(sum != mst){                        ans++;                }        }    }    printf("%d\n",ans);}//int main()//{//freopen("C:/OJ/in.txt","r",stdin);//    while( ~scanf("%d%d", &n, &m) && n + m)//    {//        init();//        input();//        prim();//        solve();//        query();//    }//    return 0;//}int main(){        #ifndef ONLINE_JUDGE        freopen("C:/OJ/in.txt","r",stdin);    #endif    int T;scan(T);    while(T--){                scan(n);                m=n-1;                init();                input();               // cerr<<"start:"<<map[0][1]<<endl;                prim();                //std::cerr<<mst<<std::endl;                solve();                query();               // cerr<<"end:"<<map[0][1]<<endl;    }}

0 0
原创粉丝点击