1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int qw[10001]={0},tj[10001]={0}; 7 int n; 8 cin>>n; 9 long long ans=-n*200; 10 for(int i=1;i<=n;i++) 11 cin>>tj[i]; 12 for(int i=1;i<=n;i++) 13 cin>>qw[i]; 14 sort(tj,tj+n+1); 15 sort(qw,qw+n+1); 16 for(int i=1;i<=n;i++) 17 { 18 for(int j=n;j>=1;j--) 19 { 20 if(tj[i]>qw[j]){qw[j]=999999;ans+=400;break;} 21 else if(tj[i]==qw[j]){qw[j]=999999;ans+=200;break;} 22 } 23 } 24 cout<<max(0,ans); 25 system("pause"); 26 return 0; 27 }
|
但是用最弱的马故意输最强的马当然也是不可取的。
网上有种贪心做法是这样
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 using namespace std; 5 const int Max=10000; 6 int tian[Max],king[Max]; 7 int i,j,n; 8 bool cmp(int a,int b) {return a>b;} 9 int main() 10 { 11 cin>>n; 12 for(i=1;i<=n;i++) {cin>>tian[i];} 13 for(i=1;i<=n;i++) {cin>>king[i];} 14 sort(tian+1,tian+1+n,cmp); 15 sort(king+1,king+1+n,cmp); 16 int ans=0; 17 int ii,jj; 18 for(i=1,j=1,ii=n,jj=n;i<=ii;) 19 { 20 if(tian[i]>king[j]){ans+=200;i++,j++;} 21 else if(tian[i]<king[j]){ans-=200;j++,ii--;} 22 else 23 { 24 if(tian[ii]>king[jj]) 25 { 26 ans+=200; 27 ii--;jj--; 28 } 29 else 30 { 31 if(tian[ii]<king[j]) 32 ans-=200; 33 ii--,j++; 34 } 35 } 36 } 37 cout<<ans; 38 return 0; 39 }
1.思路
不妨用贪心思想来分析一下问题。因为田忌掌握有比赛的“主动权”,他总是根据齐王所出的马来分配自己的马,所以这里不妨认为齐王的出马顺序是按马的速度从高到低出的。由这样的假设,我们归纳出如下贪心策略:
如果田忌剩下的马中最强的马都赢不了齐王剩下的最强的马,那么应该用最差的一匹马去输给齐王最强的马。
如果田忌剩下的马中最强的马可以赢齐王剩下的最强的马,那就用这匹马去赢齐王剩下的最强的马。
如果田忌剩下的马中最强的马和齐王剩下的最强的马打平的话,可以选择打平或者用最差的马输掉比赛。
2.反例
光是打平的话,如果齐王马的速度分别是1 2 3,田忌马的速度也是1 2 3,每次选择打平的话,田忌一分钱也得不到,而如果选择先用速度为1的马输给速度为3的马的话,可以赢得200两黄金。
光是输掉的话,如果齐王马的速度分别是1 3,田忌马的速度分别是2 3,田忌一胜一负,仍然一分钱也拿不到。而如果先用速度为3的马去打平的话,可以赢得200两黄金。
3.解决方案
通过上述的三种贪心策略,我们可以发现,如果齐王的马是按速度排序之后,从高到低被派出的话,田忌一定是将他马按速度排序之后,从两头取马去和齐王的马比赛。有了这个信息之后,动态规划的模型也就出来了!
4.DP方程
设f[i,j]表示齐王按从强到弱的顺序出马和田忌进行了i场比赛之后,从“头”取了j匹较强的马,从“尾”取了i-j匹较弱的马,所能够得到的最大盈利。
状态转移方程如下:
F[I,j]=max{f[i-1,j]+c[n-(i-j)+1,i],f[i-1,j-1]+c[j,i]}
其中g[i,j]表示田忌的马和齐王的马分别按照由强到弱的顺序排序之后,田忌的第i匹马和齐王的第j匹马赛跑所能取得的盈利,胜为1,输为-1,平为0。
结果用最大的乘以200即可。
5.解释
为什么F[I,j]=max{f[i-1,j]+c[n-(i-j)+1,i],f[i-1,j-1]+c[j,i]}可以呢?
因为你无论怎么样都是从前或者从后面取马,而F[I,j]=max{f[i-1,j]+c[n-(i-j)+1,i],f[i-1,j-1]+c[j,i]}这个方程把所有可能的贪心情况都表示出来了。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int f[3001][3001],a[3001],b[3001],c[3001][3001]; 6 int n,ans=0; 7 bool gz(int a,int b) {return a>b;} 8 int main() 9 { 10 cin>>n; 11 for(int i=0;i<=n;i++) 12 for(int j=0;j<=n;j++) 13 f[i][j]=-999999; 14 for(int i=1;i<=n;i++)cin>>a[i]; 15 for(int i=1;i<=n;i++)cin>>b[i]; 16 sort(a+1,a+n+1,gz); 17 sort(b+1,b+n+1,gz); 18 for(int i=1;i<=n;i++) 19 for(int j=1;j<=n;j++) 20 if(a[i]>b[j])c[i][j]=1; 21 else if(a[i]==b[j])c[i][j]=0; 22 else c[i][j]=-1; 23 f[0][0]=0; 24 for(int i=1;i<=n;i++) 25 for(int j=0;j<=i;j++) 26 if(j>=1)f[i][j]=max(f[i-1][j]+c[n-(i-j)+1][i],f[i-1][j-1]+c[j][i]); 27 else f[i][j]=f[i-1][j]+c[n-(i-j)+1][i]; 28 for(int i=0;i<=n;i++) 29 ans=max(f[n][i],ans); 30 cout<<ans*200; 31 return 0; 32 }
泡泡堂
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=1e7+7; 6 int n,l1,r1,l2,r2,ret; 7 int a[maxn],b[maxn]; 8 bool cmp(int a,int b){return a<b;} 9 int proc(int *a,int *b){ 10 l1=l2=1;r1=r2=n;ret=0; 11 while(l1<=r1&&l2<=r2){ 12 if(a[l1]>b[l2]){ 13 ret+=2;l1++;l2++; 14 } 15 else{ 16 if(a[r1]>b[r2]){ //a[r1]==b[r2]或者a[r1]<b[r2]后面可能会用到a[r1] 17 ret+=2;r1--;r2--; 18 } 19 else{ 20 if(a[l1]==b[r2]){//here 21 ret++; 22 } 23 l1++;r2--; 24 } 25 } 26 } 27 return ret; 28 } 29 int main(){ 30 cin>>n; 31 for(int i=1;i<=n;i++) cin>>a[i]; 32 for(int i=1;i<=n;i++) cin>>b[i]; 33 sort(a+1,a+n+1,cmp);sort(b+1,b+n+1,cmp); 34 cout<<proc(a,b)<<" "<<2*n-proc(b,a)<<endl; 35 return 0; 36 }
这里面有一个小小的转化,要灵活
大概就是无论从小到大排还是从大到小排都行,但有一点不太一样
假设是从小到大排序:
每次都应该选最小的比它大的,但是,因为是已经排好序的,所以不必每局或者二分,直接挨个跳就行了,无论是从前计算还是从后计算都是这样
到了here的时候,如果a[r1]<b[l2],那么结局已定,直接减去就好啦