码迷,mamicode.com
首页 > 其他好文 > 详细

hdu4009 Transfer water 最小树形图

时间:2014-08-28 21:05:46      阅读:396      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   os   io   for   问题   div   log   

  每一户人家水的来源有两种打井和从别家接水,每户人家都可能向外输送水。

  打井和接水两种的付出代价都接边。设一个超级源点,每家每户打井的代价就是从该点(0)到该户人家(1~n)的边的权值。接水有两种可能,从高处接水,那么代价是哈密顿距离与Y的乘积(可以认为就是水管的费用);从低处接水,还要加上付出水泵的钱(水管+水泵的费用)。这样就可以建图了。图论,会建图的话问题就解决一半了。

  然后,用模版来解题。不过朱刘算法的模版时间复杂度的差异还是蛮大的。我的模版的建图是邻接矩阵,时间复杂度是O(N^3)。超时,过不了。在网上找了一份按边的起点、终点、权值建图的模版。AC了。该算法的复杂度是O(M)。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1010, M=1010000,INF=0x3f3f3f3f;
int pre[N],id[N],in[N],vis[N];
int tot;//边数
struct node
{
    int u,v,w;
}e[M];
void adde(int i,int j,int k)
{
    e[tot].u=i;e[tot].v=j;e[tot++].w=k;
}
int zhuliu(int root ,int vn)
{
    int ans=0;
    int cnt;
    while(1)
    {
        for(int i=0;i<vn;i++)
            in[i]=INF,id[i]=-1,vis[i]=-1;
        for(int i=0;i<tot;i++)
        {
            if(in[e[i].v]>e[i].w && e[i].u!=e[i].v)
            {
                pre[e[i].v]=e[i].u;
                in[e[i].v]=e[i].w;
            }
        }
        in[root]=0;
        pre[root]=root;
        for(int i=0;i<vn;i++)
        {
            ans+=in[i];
            if(in[i]==INF)//这一步可以看出是否存在这样一棵树形图,因此可以略去DFS
                return -1;
        }
        cnt=0;
        for(int i=0;i<vn;i++)
        {
            if(vis[i]==-1)
            {
                int t=i;
                while(vis[t]==-1)
                {
                    vis[t]=i;
                    t=pre[t];
                }
                if(vis[t]!=i || t==root) continue;
                for(int j=pre[t];j!=t;j=pre[j])
                    id[j]=cnt;
                id[t]=cnt++;
            }
        }
        if(cnt==0) break;
        for(int i=0;i<vn;i++)
            if(id[i]==-1)
                id[i]=cnt++;
        for(int i=0;i<tot;i++)
        {
            int u,v;
            u=e[i].u;
            v=e[i].v;
            e[i].u=id[u];
            e[i].v=id[v];
            e[i].w-=in[v];
        }
        vn=cnt;
        root=id[root];
    }
    return ans;
}

struct Node
{
    int a,b,c;
}nd[N];
int main()
{
    //freopen("test.txt","r",stdin);
    int n,x,y,z,i,j,k,d;
    while(scanf("%d%d%d%d",&n,&x,&y,&z)!=EOF)
    {
        if(!n) break;
        tot=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&nd[i].a,&nd[i].b,&nd[i].c);
            adde(0,i,nd[i].c*x);
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&j);
                if(i==j) continue;
                d=abs(nd[i].a-nd[j].a)+abs(nd[i].b-nd[j].b)+abs(nd[i].c-nd[j].c);
                d*=y;
                if(nd[i].c<nd[j].c)  d+=z;
                adde(i,j,d);
            }
        }
        int ans=zhuliu(0,n+1);
        if(ans==-1) printf("poor XiaoA\n");
        else printf("%d\n",ans);
    }
    return 0;
}

 

 

下面是邻接矩阵建图的模版,虽然超时了。但是模版还是有借鉴意义的。模版来自哈工大出版的《图论及应用》。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1010, INF=0x3f3f3f3f;
int Map[N][N];
bool vis[N],f[N];
//f是缩点标记,1表示该点已经被缩掉
int pre[N];
int zhuliu(int n)
{
    int sum=0;
    int i,j,k;
    for(i=0;i<n;i++)
    {
        f[i]=0;
        Map[i][i]=INF;
    }
    pre[0]=0;
    while(1)
    {
        //求最短弧集合E0
        for(i=1;i<n;i++)
        {
            if(f[i]) continue;
            pre[i]=i;
            for(j=0;j<n;j++)
                if(!f[j]&&Map[j][i]<Map[pre[i]][i])  pre[i]=j;
            if(pre[i]==i) return -1; //没有入边,不存在最小树形图
        }
        //检查E0
        for(i=1;i<n;i++)
        {
            if(f[i]) continue ;
            //从当前点开始找环
            for(j=0;j<n;j++) vis[j]=0;
            vis[0]=1;
            j=i;
            do
            {
                vis[j]=1;
                j=pre[j];
            }
            while(!vis[j]) ;
            if(!j) continue; //没有找到环
            //收缩G中的有向环
            i=j;
            //将整个环的权值保存,累计入原图的最小树形图
            do
            {
                sum+=Map[pre[j]][j];
                j=pre[j];
            }
            while(j!=i) ;
            j=i;
            //对与环上的点有关的边,修改边权
            do
            {
                for(k=0; k<n; k++)
                    if(!f[k]&&Map[k][j]<INF&&k!=pre[j])
                        Map[k][j]-= Map[pre[j]][j];
                j=pre[j];
            }
            while(j!=i) ;
            //缩点,将整个环缩成i号点,所有与环上的点有关的边转移到点i
            for(j=0;j<n;j++)
            {
                if(j==i) continue;
                for(k=pre[i]; k!=i; k=pre[k])
                {
                    if(Map[k][j]<Map[i][j]) Map[i][j] =Map[k][j];
                    if(Map[j][k]<Map[j][i]) Map[j][i] =Map[j][k];
                }
            }
            //标记环上其他的点为被缩掉
            for(j=pre[i];j!=i;j=pre[j]) f[j] =1;
            //当前环缩点结束,形成新的图G’,跳出继续求G’的最小树形图
            break;
        }
        //如果所有的点都被检查且没有环存在,现在的最短弧集合E0就是
        //最小树形图,累计如sum, 算法结束
        if(i==n)
        {
            for(i=1;i<n;i++) if(!f[i]) sum+=Map[pre[i]][i];
            break;
        }
    }
    return sum;
}

struct node
{
    int a,b,c;
}nd[N];
int main()
{
    //freopen("test.txt","r",stdin);
    int n,x,y,z,i,j,k,d;
    while(scanf("%d%d%d%d",&n,&x,&y,&z)!=EOF)
    {
        if(!n) break;
        for(i=0;i<=n;i++)
            for(j=0;j<i;j++)
                Map[j][i]=Map[i][j]=INF;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&nd[i].a,&nd[i].b,&nd[i].c);
            Map[0][i]=nd[i].c*x;
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&j);
                if(i==j) continue;
                d=abs(nd[i].a-nd[j].a)+abs(nd[i].b-nd[j].b)+abs(nd[i].c-nd[j].c);
                d*=y;
                if(nd[i].c>=nd[j].c)  d+=z;
                Map[i][j]=min(d,Map[i][j]);
            }
        }
        printf("%d\n",zhuliu(n+1));
    }
    return 0;
}

 

hdu4009 Transfer water 最小树形图

标签:style   blog   color   os   io   for   问题   div   log   

原文地址:http://www.cnblogs.com/Potato-lover/p/3942321.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!