Problem B. Cards Game Google Kickstart Round G 2017

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yixin94/article/details/82053897

题意:有一组卡片,正反面的值是R[i],B[i],每次选择两个卡片i,j把min(R[i]^B[j],B[i]^R[j])加到value中,再将其中一个卡片放回,直到只剩一张卡片。问最优策略下最小的value是多少。

small input可以用dp,状态用二进制数表示,比如N=5,10101表示余下第0,2,4个卡片,状态转移时枚举选取其中两个卡片,再放回去一个。

large input真心想不到最小生成树上面去。切入点是假设最优解中的操作次序是选择卡片a,b,移除卡片b,那么说明a把b移除了,接下来选择卡片a,c,移除卡片a,a又被c移除,不可能出现的情况就是同时选了b,c,b把c移除或者c把b移除。Then 如果卡片之间连一条边,最优解中不可能出现环。因此就是个求最小生成树的问题。

卡片i,j之间连一条无向边,weight=min(R[i]^B[j],B[i]^R[j])。再求最小生成树即可。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<windows.h>
using namespace std;

//Kcikstart 2017 Round D Problem B. Cards Game
const int maxn=110;
int T;
int N;
long long R[maxn];
long long B[maxn];
long long mp[maxn][maxn];
int p[maxn*maxn];// disjoint-sets forest
int E;
long long ans;
class edge
{
public:
    int a;
    int b;
    long long weight;
    edge()
    {
        a=0;
        b=0;
        weight=0;
    }
    edge(int a0,int b0,long long w0)
    {
        a=a0;
        b=b0;
        weight=w0;
    }
    bool operator < (edge other) const
    {
        return weight<other.weight;
    }
    bool operator > (edge other) const
    {
        return weight>other.weight;
    }
    bool operator == (edge other) const
    {
        return weight==other.weight;
    }
};
edge edge_set[maxn*maxn];

int init()
{
    for (int i=0;i<maxn*maxn;++i)
    {
        p[i]=i;
    }
}
int find(int x)
{
    if(x==p[x])
    {
        return x;
    }
    else
    {
        return p[x]=find(p[x]);
    }
}
void Union(int x,int y)
{
    p[find(x)]=find(y);
}

void Kruskal()
{
    init();
    sort(edge_set, edge_set+E);
//    for(int i=0;i<E;i++)
//    {
//        cout<<edge_set[i].a<<" "<<edge_set[i].b<<" "<<edge_set[i].weight<<endl;
//    }
    int j=0;
    while(j<E)
    {
        while(find(edge_set[j].a)==find(edge_set[j].b))
        {
//            cout<<edge_set[j].a<<" "<<edge_set[j].b<<" "<<p[edge_set[j].a]<<" "<<p[edge_set[j].b]<<endl;
            j++;
            if(j>=E)
            {
                return;
            }
//            cout<<j<<endl;
        }
        Union(edge_set[j].a,edge_set[j].b);
//        cout<<"add edge "<<edge_set[j].a<<" "<<edge_set[j].b<<endl;
        ans+=edge_set[j].weight;
        j++;
    }
}
int main()
{
//    freopen("input.txt","r",stdin);

    freopen("B-small-practice.in","r",stdin);
    freopen("B.txt","w",stdout);
    cin>>T;

    for(int ca=1;ca<=T;ca++)
    {
        memset(R,0,sizeof(R));
        memset(B,0,sizeof(B));
        memset(mp,0,sizeof(mp));
        memset(p,0,sizeof(p));
        memset(edge_set,0,sizeof(edge_set));
        scanf("%d",&N);
        E=0;
        ans=0;
        for(int i=0;i<N;i++)
        {
            scanf("%lld",&R[i]);
        }
        for(int i=0;i<N;i++)
        {
            scanf("%lld",&B[i]);
        }
//        for(int i=0;i<N;i++)
//        {
//            cout<<R[i]<<" "<<B[i]<<endl;
//        }
        for(int i=0;i<N;i++)
        {
            for(int j=i+1;j<N;j++)
            {
                int weight=min(R[i]^B[j],R[j]^B[i]);
//                cout<<weight<<" "<<(R[i]^B[j])<<" "<<(R[j]^B[i])<<endl;
                mp[i][j]=weight;
                mp[j][i]=weight;
                edge_set[E++]=edge(i,j,weight);
            }
        }
//        for(int i=0;i<N;i++)
//        {
//            for(int j=0;j<N;j++)
//            {
//                cout<<mp[i][j]<<" ";
//            }
//            cout<<endl;
//        }
        Kruskal();
        printf("Case #%d: %lld\n",ca,ans);


    }
    return 0;
}

附dp code for small input

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<climits>
using namespace std;

//kickstart 2017 Round G Problem B
int T;
const int maxn=1<<6;
int N;
int M;
long long ans;
long long dp[maxn];
int used[maxn];
long long R[10];
long long B[10];
long long dfs(int state)
{
    //cout<<"state "<<bitset<5>(state)<<endl;
    if(used[state]==true)
    {
        return dp[state];
    }
    int cardnum=0;
    int cardidx[N];
    memset(cardidx,0,sizeof(cardidx));
    for(int i=0;i<N;i++)
    {
        //cout<<"check "<<bitset<5>((1<<i))<<" "<<((1<<i)&state)<<endl;
        if(((1<<i)&state)!=0)
        {
            cardnum++;
            cardidx[i]=1;
            //cout<<i<<endl;
        }
    }
    if(cardnum==1)
    {
        dp[state]=0;
        return 0;
    }
    int card1=0;
    int card2=0;
    long long minret=LLONG_MAX;
    //bool chg=false;
    for(int i=0;i<N;i++)
    {
        if(cardidx[i]==1)
        {
            card1=i;
            for(int j=i+1;j<N;j++)
            {
                if(cardidx[j]==1)
                {
                    card2=j;
                    long long curr=min(R[card1]^B[card2],R[card2]^B[card1]);
                    //cout<<curr<<" "<<minret<<" "<<(minret-curr)<<endl;
                    int nextstate=state^(1<<card1);
                    minret=min(minret,curr+dfs(nextstate));
                    nextstate=state^(1<<card2);
                    minret=min(minret,curr+dfs(nextstate));

                    //chg=true;
                }
            }
        }
    }
//    if(chg==false)
//    {
//        cout<<"unchanged "<<bitset<5>(state)<<endl;
//    }
    //cout<<bitset<5>(state)<<" "<<minret<<endl;
    dp[state]=minret;
    used[state]=true;
    return minret;
}
int main()
{
//    long long sminret=LLONG_MAX;
//    cout<<sminret<<endl;
    //cout<<(872031131^582064085)<<" "<<0x3f3f3f3f<<endl;
    freopen("B-small-attempt2.in","r",stdin);
    //freopen("input.txt","r",stdin);
    freopen("b1.txt","w",stdout);
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        ans=0;
        memset(R,0,sizeof(R));
        memset(B,0,sizeof(B));
        memset(dp,0,sizeof(dp));
        memset(used,false,sizeof(used));
        scanf("%d",&N);
        for(int i=0;i<N;i++)
        {
            dp[(1<<i)]=0;
            used[(1<<i)]=true;
            scanf("%lld",&R[i]);
        }
        for(int i=0;i<N;i++)
        {
            scanf("%lld",&B[i]);
        }
        //cout<<"init "<<((1<<N)-1)<<endl;
        ans=dfs((1<<N)-1);

        printf("Case #%d: %lld\n",ca,ans);

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yixin94/article/details/82053897