Problem B. Cards Game Google Kickstart Round G 2017
阿新 • • 發佈:2018-11-09
題意:有一組卡片,正反面的值是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; }