ICPC 铜牌题(1)

A - Little Tiger vs. Deep Monkey
题目链接
题目大意:刷题比赛,老虎做对一道题的概率是0.5,猴子随意(不用管)
求老虎总分不低于猴子的概率p的最低分。

思路:开始我想的是把所有的加和情况放进set去重,然后WA了,题目没读懂,后来看了题解,这是一道概率dp

dp数组含义:dp[i][j]表示前i个科目老虎得分为j的概率
转移方程:
dp[i+1][j+a[i]]+=dp[i][j]*0.5; //做对
dp[i+1][j]+=dp[i][j]*0.5; //没做对
两种情况,做对了这题和没做对这题

#include <bits/stdc++.h>
#define MAX 0x3f3f3f3f
using namespace std;
typedef long long ll;
int t,n;
double p;
double dp[55][50005];
int a[60];
int main(){
	cin >> t;
	while(t--){
		int sum=0;
		memset(dp,0,sizeof(dp));//重置
		scanf("%d%lf",&n,&p);
		for(int i=0; i<n; i++){
			scanf("%d",&a[i]);
			sum+=a[i];//加和求总分,方便后续dp数组分数那一栏的循环
		}
		dp[0][0]=1;
		for(int i=0; i<n; i++){
			for(int k=0; k<=sum; k++){
				if(dp[i][k]<=0) continue;
				dp[i+1][k+a[i]]+=dp[i][k]*0.5;
				dp[i+1][k]+=dp[i][k]*0.5;
			}
		}
		double ans=0;
		for(int i=0; i<=sum; i++){
			ans+=dp[n][i];//求的是做所有题,所以从n开始
			if(ans>=p){
				printf("%d\n",i);//i代表的是分数
				break;
			}
		}
	}
	return 0;
}

挺神奇的,毕竟我对dp不太了解,还可以这样解,学到了。

I - Happy Matt Friends
题目链接

题目大意:给你一个数组,对其中的元素(任意数量)进行异或操作,最后统计有多个结果大于给定的M。

思路:我开始就猜到dp,但我不会,后面查题解,发现这是一道dp位运算

dp数组含义:dp[i][j]表示前i道题中异或值为j的情况的个数。

转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j^a[i]];
取和不取两种状态

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1<<20;//注意一下,不要开0x3f3f3f3f
int t,n,m;
double p;
int dp[55][MAX*2];
int a[60];
int Case;
int main(){
	cin >> t;
	while(t--){
		ll sum=0;
		scanf("%d%d",&n,&m);
		for(int i=1; i<=n; i++) scanf("%d",&a[i]);
		dp[0][0]=1;
		for(int i=1; i<=n; i++){
			for(int j=0; j<=MAX; j++){
				dp[i][j]=dp[i-1][j]+dp[i-1][j^a[i]];
			}
		}
		for(int i=m; i<=MAX; i++){
			sum+=dp[n][i];//从大于m开始加和
		}
		printf("Case #%d: %lld\n",++Case,sum);
	}
	return 0;
}

D - Stealing Harry Potter’s Precious
题目链接

题意:一张图,‘#’不可走,‘.’可走,所有的宝物都藏在‘.’里,从‘@’位置出发,如果能找到所有的宝物,输出最短路,如果不能,输出-1。

思路:存图->记下起点->开pair数组记下所有宝物位置->开a数组记下k,用于全排列->全排列的情况下进行bfs,从原点开始,找到一个宝物然后刷新起点至宝物的点,然后不断刷新min步数->输出答案

#include <bits/stdc++.h>
#define MAX 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=105;
int n,m,k;
pii a[maxn];
char mp[maxn][maxn];//存图
int dis[maxn][maxn];//记录到当前点的步数
int dir[4][2]={-1,0,1,0,0,-1,0,1};//方向数组
int st,ed,stx,edx;
int g,h;
int b[maxn];
int bfs(int bx, int by, int ex, int ey){
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++) dis[i][j]=-1;//重置
	dis[bx][by]=0;//起点记为0
	queue<pii>q;
	q.push({bx,by});
	while(!q.empty()){
		pii t=q.front();
		q.pop();
		for(int i=0; i<4; i++){
			int tx=t.first+dir[i][0], ty=t.second+dir[i][1];
			if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&dis[tx][ty]==-1&&mp[tx][ty]=='.'){
				dis[tx][ty]=dis[t.first][t.second]+1;
				q.push({tx,ty});
			}
		}
	}
	return dis[ex][ey];//返回找到宝藏的步数
}
int main(){
	while(cin>>n>>m&&n&&m){
		for(int i=1; i<=n; i++){
			for(int j=1; j<=m; j++){
				cin>>mp[i][j];
				if(mp[i][j]=='@') st=i,ed=j;
			}
		}
		cin>>k;
		for(int i=0; i<k; i++){
			cin>>g>>h;
			a[i]={g,h};
		}
		for(int i=0; i<k; i++) b[i]=i;
		int sum=MAX;
		do{
			int res=0;
			int nowx=st, nowy=ed;
			for(int i=0; i<k; i++){//遍历一遍一种排列情况
				int w=bfs(nowx,nowy,a[b[i]].first,a[b[i]].second);
				if(w==-1){
				//-1是没有找到该宝藏,也就是不存在找到所有宝藏的通路
					sum=-1;
					goto there;
				}
				else res+=w;
				nowx=a[b[i]].first,nowy=a[b[i]].second;//更新起始点
			}
			sum=min(sum,res);//刷新最小值
		}
		while(next_permutation(b,b+k));//全排列,很好用
		there:
			printf("%d\n",sum);
	}
	return 0;
}

C - Zhuge Liang’s Password
题目链接

思路:矩阵旋转,水题。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e1+10;
int a[maxn][maxn], b[maxn][maxn], c[maxn][maxn];
int n,sum;
void turn(){
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			c[i][j]=b[n-j-1][i];
		}
	}
}
void judge(){
	int res=0;
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			if(a[i][j]==b[i][j]) res++;
		}
	}
	sum=max(sum,res);
}
int main(){
	while(cin>>n&&n){
		sum=0;
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				scanf("%d",&a[i][j]);
			}
		}
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				scanf("%d",&b[i][j]);
				c[i][j]=b[i][j];
			}
		}
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				if(a[i][j]==b[i][j]) sum++;
			}
		}
		for(int i=0; i<3; i++){
			turn();
			for(int i=0; i<n; i++){
				for(int j=0; j<n; j++){
					b[i][j]=c[i][j];
				}
			}
			judge();
		}
		printf("%d\n",sum);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值