第七届山东省ACM省赛---problem I. Rock Paper Scissors(状压统计)
problem I. Rock Paper Scissors
题目大意:
N个人剪刀包袱锤,每人和剩下的人(N-1)比赛,每场比赛出10次
输出每个人赢分别0,1,2……10次的次数
规则:
P>R S>P R>S
e.g.
first RRSSSPPPPP
second RRRRRRRRRR
第一个人赢5次,第二个人赢3次
对应输出
00000100000
00010000000
Sample
Input
2
4
RRRRRRRRRR
SSSSSSSSSS
PPPPPPPPPP
RRSSSPPPPP
6
RRRRPPPRPP
PSRSPPPPSP
RSPPRSSRRP
SPPRSRRRSS
RPPSPRSSSS
RSRRSPRSSP
Output
Case #1:
1 0 0 1 0 0 0 0 0 0 1
1 0 0 0 0 1 0 0 0 0 1
1 0 1 0 0 0 0 0 0 0 1
0 0 1 1 0 1 0 0 0 0 0
Case #2:
0 0 1 4 0 0 0 0 0 0 0
0 0 1 2 2 0 0 0 0 0 0
0 0 0 1 2 1 1 0 0 0 0
0 0 0 2 1 2 0 0 0 0 0
0 1 1 0 2 1 0 0 0 0 0
0 1 1 2 0 1 0 0 0 0 0
分析:
第一想到暴力
Time Limit Exceeded
太傻太天真
#include "cstdio" #include "cstring" #include "iostream" using namespace std; #define N 30010 char player[N][10]; int ans[11]; void solve(int n) { int cnt=0; for(int i=0;i<n;i++) { memset(ans,0,sizeof(ans)); for(int k=0;k<n;k++) { if(i==k)continue; cnt=0; for(int j=0;j<10;j++) { if(player[i][j]=='S'&&player[k][j]=='P') { cnt++; continue; } else if(player[i][j]=='P'&&player[k][j]=='R') { cnt++; continue; } else if(player[i][j]=='R'&&player[k][j]=='S') { cnt++; } } ans[cnt]++; ///cout<<"----------------------"<<cnt<<endl; } printf("%d",ans[0]); for(int i=1;i<=10;i++) printf(" %d",ans[i]); printf("\n"); } } int main() { freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); int t,n,cnt=0; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%s",player[i]); printf("Case #%d:\n",++cnt); solve(n); } fclose(stdin); fclose(stdout); return 0; }
上面解法太多重复计算的地方,仅就两两比较次数(n-1)^n
下面优化算法,避免重复计算,比较次数,c(n,2)=n*(n-1)/2;
依旧TLE
太傻太天真+1
#include "cstdio" #include "cstring" #include "iostream" using namespace std; #define N 30010 char player[N][10]; int ans[N][11];void solve(int n) { for(int i=0;i<n;i++) memset(ans[i],0,sizeof(ans[i])); int cnt1=0,cnt2=0; for(int i=0;i<n;i++) { for(int k=i+1;k<n;k++) { if(i==k)continue; cnt1=0;cnt2=0; for(int j=0;j<10;j++) { if(player[i][j]=='S'&&player[k][j]=='P') { cnt1++; continue; } else if(player[i][j]=='P'&&player[k][j]=='S') { cnt2++; continue; } else if(player[i][j]=='P'&&player[k][j]=='R') { cnt1++; continue; } else if(player[i][j]=='R'&&player[k][j]=='P') { cnt2++; continue; } else if(player[i][j]=='R'&&player[k][j]=='S') { cnt1++; } else if(player[i][j]=='S'&&player[k][j]=='R') { cnt2++; continue; } } ans[i][cnt1]++; ans[k][cnt2]++; ///cout<<"----------------------"<<cnt<<endl; } } for(int i=0;i<n;i++) { printf("%d",ans[i][0]); for(int j=1;j<=10;j++) printf(" %d",ans[i][j]); printf("\n"); } } int main() { freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); int t,n,cnt=0; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%s",player[i]); printf("Case #%d:\n",++cnt); solve(n); } fclose(stdin); fclose(stdout); return 0; }
事情并没有你想的那么简单
感谢http://www.cnblogs.com/shuguangzw/p/5585715.html
状压统计
就是改成把一个字符串改成三进制状压,然后分成前5位,后5位统计,
然后直接统计 f[i][j][k]代表,后5局状压为k的,前5局比和j状态比输了5局的有多少个人
复杂度是O(T*30000*25*m)m比较小,也就最多几十吧,将将过
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdlib> #include <vector> #include <cmath> #include <queue> #include <map> #include <string> using namespace std; typedef long long LL; const int N=3e4+5; const int M=243; const int INF=0x3f3f3f3f; int get(int x,int y){ int ret=0; for(int k=0;k<5;++k){ int dig0=x%3,dig1=y%3; if(dig0==(dig1+1)%3)++ret; x/=3,y/=3; } return ret; } vector<int> win[6][M],lose[6][M]; int T,cas,n,a[N][11],ret[N][11],f[6][M][M]; char ch[15]; int main(){ for(int i=0;i<M;++i){ for(int j=0;j<M;++j){ win[get(i,j)][i].push_back(j); lose[get(i,j)][j].push_back(i); } } scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;++i) { scanf("%s",ch); for(int j=0;j<10;++j) { if(ch[j]=='R')a[i][j]=0; else if(ch[j]=='P')a[i][j]=1; else a[i][j]=2; } } memset(f,0,sizeof(f)); memset(ret,0,sizeof(ret)); for(int i=0;i<n;++i) { int mask0=0,mask1=0; for(int j=0;j<5;++j)mask0=mask0*3+a[i][j]; for(int j=5;j<10;++j)mask1=mask1*3+a[i][j]; for(int j=0;j<=5;++j) { for(int k=0;k<lose[j][mask0].size();++k) { int t=lose[j][mask0][k]; ++f[j][t][mask1]; } } } for(int i=0;i<n;++i){ int mask0=0,mask1=0; for(int j=0;j<5;++j)mask0=mask0*3+a[i][j]; for(int j=5;j<10;++j)mask1=mask1*3+a[i][j]; for(int s0=0;s0<=5;++s0) for(int s1=0;s1<=5;++s1){ for(int k=0;k<win[s1][mask1].size();++k){ int t=win[s1][mask1][k]; ret[i][s0+s1]+=f[s0][mask0][t]; } } --ret[i][0]; } printf("Case #%d:\n",++cas); for(int i=0;i<n;++i){ for(int j=0;j<10;++j) printf("%d ",ret[i][j]); printf("%d\n",ret[i][10]); } } return 0; }

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号