比赛地址:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17674#overview
第一题:这题给你一个棋盘的两个格子,问国王从第一个格子到第二个格子的最短路
分析:签到题,仔细讨论情况基本没问题,贴下我代码:
#include<cmath> #include<cstdio> #include<iostream> using namespace std; char a[9],b[9]; int main() { while(~scanf("%s%s",a,b)) { printf("%d\n",(int)max(fabs(a[0]-b[0]),fabs(a[1]-b[1]))); if(a[0]<b[0]) { if(a[1]>b[1]) { while(a[0]<b[0]&&a[1]>b[1]) { puts("RD"); ++a[0],--a[1]; } while(a[0]++<b[0])puts("R"); while(a[1]-->b[1])puts("D"); } else { while(a[0]<b[0]&&a[1]<b[1]) { puts("RU"); ++a[0],++a[1]; } while(a[0]++<b[0])puts("R"); while(a[1]++<b[1])puts("U"); } } else { if(a[1]>b[1]) { while(a[0]>b[0]&&a[1]>b[1]) { puts("LD"); --a[0],--a[1]; } while(a[0]-->b[0])puts("L"); while(a[1]-->b[1])puts("D"); } else { while(a[0]>b[0]&&a[1]<b[1]) { puts("LU"); --a[0],++a[1]; } while(a[0]-->b[0])puts("L"); while(a[1]++<b[1])puts("U"); } } } return 0; }
分析:第一眼看到,肯定会认为是背包问题啦,但是会发现v太大,根本没办法转移,这种情况下必然想到贪心,而且很明显,按性价比排序(也就是c/v来排序),取前面几个就行,但是有些情况会刚好剩下一格的体积,此时必须讨论,是否替换出前面的一个c最小且体积为1的装置,来放接下来这个体积为2的装置,这个还得考虑后面体积为1的装置与要替换装置的容量和,与当前这个体积为2的装置的容量,好吧,不好描述,具体看我的代码,仔细思考都不会有问题的:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int mm=111111; struct data { int v,p,id,w; }g[mm]; int i,j,k,n,v; long long ans; bool cmp(data a,data b) { return a.w>b.w; } bool cmp2(data a,data b) { return a.id>b.id; } int main() { while(~scanf("%d%d",&n,&v)) { for(i=0;i<n;++i) { scanf("%d%d",&g[i].v,&g[i].p); g[i].id=i+1,g[i].w=g[i].p; if(g[i].v==1)g[i].w<<=1;; } sort(g,g+n,cmp); for(ans=i=j=0;i<n;++i) if(j+g[i].v<=v) { j+=g[i].v; ans+=g[i].p; } else break; if(j<v&&i<n) { g[n].p=0; for(k=i+1;k<n;++k) if(g[k].v==1)break; for(j=i-1;j>=0;--j) if(g[j].v==1)break; if(j>=0&&g[j].p+g[k].p<g[i].p) { ans+=g[i].p-g[j].p; swap(g[j],g[i]); } else if(k<n) { swap(g[i],g[k]); ans+=g[i++].p; } } cout<<ans<<endl; sort(g,g+i,cmp2); while(i--)printf("%d%c",g[i].id,i?' ':'\n'); } return 0; }
分析:这题纯粹的分类讨论吧,假设当前有a个X,b个0,那么a<b或 a-b>1都是非法情况,接下来考虑是否有获胜情况,这个注意下三个.不是获胜(我这里wa了一次),然后就是记录是谁获胜,这里如果两个人都为获胜状态,肯定是非法的,接下来,每个人可能有2次获胜状态,不一定只有一次(这里wa了一次),然后考虑,当第一个人获胜时,a>b,否则非法;第二人获胜,则,a==b;否则非法,剩下的如果a+b==9则平局,否则若a==b,则该第二人画了
代码:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; char map[9][9]; int i,j,a,b; int check() { for(a=b=i=0;i<3;++i) for(j=0;j<3;++j) if(map[i][j]=='X')++a; else if(map[i][j]=='0')++b; if(a<b||a-b>1)return 0; int s=0,t=0; for(i=0;i<3;++i) if(map[i][0]!='.'&&map[i][0]==map[i][1]&&map[i][0]==map[i][2])++s,t|=map[i][0]; for(j=0;j<3;++j) if(map[0][j]!='.'&&map[0][j]==map[1][j]&&map[0][j]==map[2][j])++s,t|=map[0][j]; if(map[1][1]!='.'&&map[0][0]==map[1][1]&&map[0][0]==map[2][2])++s,t|=map[1][1]; if(map[1][1]!='.'&&map[0][2]==map[1][1]&&map[0][2]==map[2][0])++s,t|=map[1][1]; if(s>0&&t==120)return 0; if(s>0&&a==b&&t=='X')return 0; if(s>0&&a>b&&t=='0')return 0; if(s>0)return ((t=='0')+3); if(a+b==9)return 5; if(a==b)return 1; return 2; } int main() { for(i=0;i<3;++i) scanf("%s",map[i]); i=check(); if(i==0)puts("illegal"); if(i==1)puts("first"); if(i==2)puts("second"); if(i==3)puts("the first player won"); if(i==4)puts("the second player won"); if(i==5)puts("draw"); return 0; }
分析:这题比赛时想了一个多小时也没想明白,一直往网络流方向想了,到后来觉得是贪心,但是还是没想出来,下面是看了题解后知道的。
假设(的值为1,)的值为-1,sum[i]为从1到i的括号值的和,
那么开始贪心了,从左往右扫描,遇到( 则sum加1,遇到 ) 则sum减1,遇到?呢,此时我们sum减1,并把?变成 ),在答案里加上b[i],并将当前值a[i]-b[i]还有位置i,保存起来(仔细看看a[i]-b[i],只要加上这个值,刚好就是将)改成( 了,呵呵)
当sum<0时,此时如果再不管它,就是非法的了(右括号比左括号多),那么我们在之前保存的东西,可以挽回这个情况,当然,为了使答案最小,我们取a[i]-b[i]最小的那个 ?(已经是)了) ,并且将它转化成(,之前记录位置了,答案加a[i]-b[i],sum加2。。。
就这样,最后判断sum是否为0,就行,为零就输出解了,至于怎么查找最小的值,这个用最小堆来维护就行(当然,你也可以用stl的优先队列来搞,具体我不会用,只能手写了,挫爆了T_T)
贪心+堆,挺好的!!
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; typedef long long LL; const int mm=111111; struct heap { int v[mm],p[mm]; int size; void change(int i,int j) { swap(v[i],v[j]); swap(p[i],p[j]); } void siftup(int k) { int i=k,j=i>>1; while(j>=1) { if(v[i]<v[j]) { change(i,j); i=j,j=i>>1; } else break; } } void siftdown(int k) { int i=k,j=k<<1; while(j<=size) { if(j<size&&v[j+1]<v[j])++j; if(v[i]>v[j]) { change(i,j); i=j,j=i<<1; } else break; } } void insert(int vv,int pp) { ++size; v[size]=vv; p[size]=pp; siftup(size); } void del() { if(!size)return; change(1,size); --size; siftdown(1); } }g; int a[mm],b[mm]; char s[mm]; int n,m; LL ans; LL solve() { int i,j,sum=0; g.size=0; LL ret=0; for(m=i=0;i<n;++i) if(s[i]=='?')++m; for(i=0;i<m;++i)scanf("%d%d",&a[i],&b[i]); for(j=i=0;i<n;++i) { if(s[i]=='(')++sum; else if(s[i]==')')--sum; else s[i]=')',--sum,ret+=b[j],g.insert(a[j]-b[j],i),++j; if(sum<0) { if(g.size<=0)return -1; ret+=g.v[1]; s[g.p[1]]='('; sum+=2; g.del(); } } if(sum)return -1; return ret; } int main() { while(~scanf("%s",s)) { n=strlen(s); ans=solve(); cout<<ans<<endl; if(ans!=-1)puts(s); } return 0; }