ZOJ 3613

来源:互联网 发布:守望先锋数据查询不了 编辑:程序博客网 时间:2024/04/29 05:19

斯坦纳树

#include<cstdio>#include<cstring>#include<queue>#define N 210#define M 5100using namespace std;int a[N],b[N];int a1[N],b1[N];int st[N],dp[N][1000],ans[1000];bool vis[N][1000];struct Edge{    int v,w,next;}edge[M*2];int n,m,k,K,ans2;int head[N],cnt;queue<int>q;void addedge(int u,int v,int w){    edge[cnt].v=v;    edge[cnt].w=w;    edge[cnt].next=head[u];    head[u]=cnt++;    edge[cnt].v=u;    edge[cnt].w=w;    edge[cnt].next=head[v];    head[v]=cnt++;}void init(){    memset(head,-1,sizeof(head));    memset(st,0,sizeof(st));    memset(dp,-1,sizeof(dp));    memset(vis,0,sizeof(vis));    memset(ans,-1,sizeof(ans));    cnt=0;}void SPFA(){    int i;    while(!q.empty()){        int x=q.front()/10000,y=q.front()%10000;        vis[x][y]=0;        q.pop();        for(i=head[x];i!=-1;i=edge[i].next){            int v=edge[i].v;            if(dp[v][st[v]|y]==-1 || dp[v][st[v]|y]>dp[x][y]+edge[i].w){                dp[v][st[v]|y]=dp[x][y]+edge[i].w;                if(!vis[v][st[v]|y] && (st[v]|y)==y){                    vis[v][st[v]|y]=1;                    q.push(v*10000+(st[v]|y));            //一定要加括号                }            }        }    }}void Steiner_Tree(){    int i,j,p,x;    for(p=0;p<K;p++){        for(i=1;i<=n;i++){            if(st[i] && (st[i]&p)==0)continue;            for(x=(p-1)&p;x;x=(x-1)&p)                if(dp[i][x|st[i]]!=-1 && dp[i][(p-x)|st[i]]!=-1)                    if(dp[i][p]==-1 || (dp[i][p]>dp[i][x|st[i]]+dp[i][(p-x)|st[i]]))                        dp[i][p]=dp[i][x|st[i]]+dp[i][(p-x)|st[i]];            if(dp[i][p]!=-1){                q.push(i*10000+p);                vis[i][p]=1;            }        }        SPFA();    }}bool check(int u){    int i,a2=0,b2=0;    for(i=0;i<k;i++)        if(u&(1<<i)){            a2+=a1[i];            b2+=b1[i];        }    return b2<=a2;}int cout(int u){    int i,a2=0,b2=0;    for(i=0;i<k;i++)        if(u&(1<<i)){            a2+=a1[i];            b2+=b1[i];        }    return min(a2,b2);}void solve(){    int i,j;    int num=0,ans1=0;    for(i=0;i<K;i++)        for(j=1;j<=n;j++)            if(dp[j][i]!=-1)                if(ans[i]==-1 || ans[i]>dp[j][i])                    ans[i]=dp[j][i];    for(i=0;i<K;i++){        //if(check(i)){           //这里只需去找那些工厂大于等于resource planets个数的状态即可            for(j=(i-1)&i;j;j=(j-1)&i)                if((check(i) && check(j) && check(i-j)) || (!check(i) && !check(j) && !check(i-j))) //或者找划分中工厂个数与resource planets个数不等式同方向的                    if(ans[j]!=-1 && ans[i-j]!=-1)                        if(ans[i]==-1 || ans[i]>ans[j]+ans[i-j])                            ans[i]=ans[j]+ans[i-j];            int cou=cout(i);            if(ans[i]!=-1)    //一定要加这个判断                if(cou>num || (cou==num && ans[i]<ans1))                    num=cou,ans1=ans[i];        //}    }    printf("%d %d\n",num/*+ans2*/,ans1);}int main(){    int i,u,v,w;    while(scanf("%d",&n)==1){        k=ans2=0;        init();        for(i=1;i<=n;i++){            scanf("%d %d",&a[i],&b[i]);            /*if(a[i]&&b[i]){                a[i]--;                b[i]--;                ans2++;            }*/            if(a[i]||b[i]){                a1[k]=a[i],b1[k]=b[i];                st[i]=1<<(k++);                dp[i][st[i]]=0;            }        }        K=1<<k;        scanf("%d",&m);        for(i=1;i<=m;i++){            scanf("%d %d %d",&u,&v,&w);            addedge(u,v,w);        }        Steiner_Tree();        solve();    }    return 0;}



原创粉丝点击