比赛地址: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的车,往里面装一些设备,使得这些装置的容量最大
分析:第一眼看到,肯定会认为是背包问题啦,但是会发现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;
}
第三题:给你一个3*3的棋盘,两个人在上面轮流画0或者X,X先画,问当前棋盘的状况
分析:这题纯粹的分类讨论吧,假设当前有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;
}