Codeforces 3

A. Shortest path of the king

        题目地址:http://codeforces.com/contest/3/problem/A

        题目大意:求8*8的棋盘上一个点到还有一个点的最短路径。

        算法讨论:优先斜着走,走到同一直线后直着走。

        Code:

#include <cstdio>

#define N 10000

using namespace std;

char c,ch;
int x1,y1,x2,y2,ans,a[N+10];

char get(){
	while (!(c>='0' && c<='9' || c>='a' && c<='h')) c=getchar();
	char tc=c;
	c=getchar();
	return tc;
}

int main(){
	ch=get();
	x1=ch-'a'+1;
	ch=get();
	y1=ch-'0';
	ch=get();
	x2=ch-'a'+1;
	ch=get();
	y2=ch-'0';
	//L-1
	//R-2
	//U-3
	//D-4
	//LU-5
	//LD-6
	//RU-7
	//RD-8
	while (x1<x2 && y1<y2) a[ans++]=7,x1++,y1++;
	while (x1<x2 && y1>y2) a[ans++]=8,x1++,y1--;
	while (x1>x2 && y1>y2) a[ans++]=6,x1--,y1--;
	while (x1>x2 && y1<y2) a[ans++]=5,x1--,y1++;
	while (x1<x2) a[ans++]=2,x1++;
	while (x1>x2) a[ans++]=1,x1--;
	while (y1<y2) a[ans++]=3,y1++;
	while (y1>y2) a[ans++]=4,y1--;
	printf("%d
",ans);
	for (int i=0;i<ans;++i)
		switch (a[i]){
			case 1:printf("L
");break;
			case 2:printf("R
");break;
			case 3:printf("U
");break;
			case 4:printf("D
");break;
			case 5:printf("LU
");break;
			case 6:printf("LD
");break;
			case 7:printf("RU
");break;
			case 8:printf("RD
");break;
		}
	return 0;
}

B. Lorry

        题目地址:http://codeforces.com/contest/3/problem/B

        题目大意:有n个物品。体积仅仅可能为1或2。每一个物品有一个体积。在给定v体积内,问最大价值是多少。

        算法讨论:

                假设没有体积1和2的限制,那么就是01背包问题。可是题中n达到10^5。v达到10^9。O(n*v)的复杂度显然不可行。

                然后考虑体积1和2的限制。我们最好还是将体积为1的和体积为2的物品分别储存,然后分别排序。

                枚举体积为1的物品的个数,那么能够计算出体积为2的物品的个数。将当前价值更新答案就可以。

        Code:

#include <cstdio>
#include <algorithm>

#define N 100000

using namespace std;

int n,v,t,p,ones,twos,value,ans,cnt;

struct node{
	int value,id,sum;
}one[N+10],two[N+10];

inline bool cmp(node a,node b){
	return a.value>b.value;
}

int main(){
	scanf("%d%d",&n,&v);
	for (int i=1;i<=n;++i){
		scanf("%d%d",&t,&p);
		if (t==1) ones++,one[ones].value=p,one[ones].id=i;
		else twos++,two[twos].value=p,two[twos].id=i;
	}
	sort(one+1,one+ones+1,cmp);
	sort(two+1,two+twos+1,cmp);
	for (int i=1;i<=ones;++i) one[i].sum=one[i-1].sum+one[i].value;
	for (int i=1;i<=twos;++i) two[i].sum=two[i-1].sum+two[i].value;
	for (int i=0,lim=min(ones,v);i<=lim;++i){
		value=one[i].sum+two[min((v-i)/2,twos)].sum;
		if (value>ans) ans=value,cnt=i;
	}
	printf("%d
",ans);
	for (int i=1;i<=cnt;++i) printf("%d ",one[i].id);
	for (int i=1,lim=min((v-cnt)/2,twos);i<=lim;++i) printf("%d ",two[i].id);
	puts("");
	return 0;
}

C. Tic-tac-toe

        题目地址:http://codeforces.com/contest/3/problem/C

        题目大意:给出一个三子棋的局面。问当前状态。

        算法讨论:模拟,注意特判。

        Code:

#include <cstdio>

using namespace std;

char s[3][3];
int a,b;
bool A,B;

inline int abs(int x){return x>0?x:-x;}

int main(){
	scanf("%s",s[0]);
	scanf("%s",s[1]);
	scanf("%s",s[2]);
	for (int i=0;i<3;++i)
		for (int j=0;j<3;++j)
			if (s[i][j]=='X') a++;
			else if (s[i][j]=='0') b++;
	if (s[0][0]=='X' && s[0][1]=='X' && s[0][2]=='X' ||
		s[1][0]=='X' && s[1][1]=='X' && s[1][2]=='X' ||
		s[2][0]=='X' && s[2][1]=='X' && s[2][2]=='X' ||
		s[0][0]=='X' && s[1][0]=='X' && s[2][0]=='X' ||
		s[0][1]=='X' && s[1][1]=='X' && s[2][1]=='X' ||
		s[0][2]=='X' && s[1][2]=='X' && s[2][2]=='X' ||
		s[0][0]=='X' && s[1][1]=='X' && s[2][2]=='X' ||
		s[0][2]=='X' && s[1][1]=='X' && s[2][0]=='X') A=1;
	if (s[0][0]=='0' && s[0][1]=='0' && s[0][2]=='0' ||
		s[1][0]=='0' && s[1][1]=='0' && s[1][2]=='0' ||
		s[2][0]=='0' && s[2][1]=='0' && s[2][2]=='0' ||
		s[0][0]=='0' && s[1][0]=='0' && s[2][0]=='0' ||
		s[0][1]=='0' && s[1][1]=='0' && s[2][1]=='0' ||
		s[0][2]=='0' && s[1][2]=='0' && s[2][2]=='0' ||
		s[0][0]=='0' && s[1][1]=='0' && s[2][2]=='0' ||
		s[0][2]=='0' && s[1][1]=='0' && s[2][0]=='0') B=1;
	if (A && B || a<b || A && a==b || B && a>b || abs(a-b)!=0 && abs(a-b)!=1){printf("illegal
");return 0;}
	if (A){printf("the first player won
");return 0;}
	if (B){printf("the second player won
");return 0;}
	if (a+b==9){printf("draw");return 0;}
	if (a==b) printf("first
");else printf("second
");
	return 0;
}

D. Least Cost Bracket Sequence

        题目地址:http://codeforces.com/contest/3/problem/D

        题目大意:给定一个括号序列,有些位置是未知的,未知位置填左右括号分别有一定代价,问使序列合法的最小代价是多少。

        算法讨论:假设全部的?都是)。然后从左到右检验括号是否匹配,假设不匹配则花费最小的代价将之前的一个?改成(。

        Code:

#include <cstdio>
#include <cstring>
#include <queue>

#define N 1000000

using namespace std;

char s[N+10];
int l,cnt,x,y;
long long ans;

struct node{
	int key,id;
};

bool operator <(node a,node b){
	return a.key<b.key;
}

priority_queue<node> Q;

int main(){
	scanf("%s",s);
	l=strlen(s);
	for (int i=0;i<l;++i){
		switch (s[i]){
			case '(':cnt++;break;
			case ')':cnt--;break;
			case '?':
				scanf("%d%d",&x,&y);
				s[i]=')';
				cnt--;
				ans+=(long long)y;
				Q.push((node){y-x,i});
				break;
		}
		if (cnt<0){
			if (Q.empty()){printf("-1
");return 0;}
			ans-=(long long)Q.top().key;
			s[Q.top().id]='(';
			Q.pop();
			cnt+=2;
		}
	}
	if (cnt) printf("-1
");
	else printf("%I64d
",ans),printf("%s
",s);
	return 0;
}

By Charlie Pan

Mar 9,2014

原文地址:https://www.cnblogs.com/mqxnongmin/p/10529643.html