算法课作业1

https://vjudge.net/contest/581138

A - Humidex

模拟题

题目大意

给三个类型数字通过公式来回转化

思路

求e的对数有log函数,不懂为什么不会出精度错误,很迷,给的三个数字也没有顺序,需要多判断。

#include<cstdio>
#include<iostream>
#include<cmath>
//Sometimes weather reports give the temperature and dewpoint,
// or the temperature and humidex
/*
D 15.0 H 34.0
D 25.0 H 42.3
E
*/
using namespace std;
int main()
{
	char a,b;
	double a1,b1;
	while(1)
	{
		cin>>a;
		if(a=='E')
			break;
		cin>>a1>>b>>b1;

		if(a=='T'&&b=='D'||a=='D'&&b=='T')
		{ 
			if(a=='D'&&b=='T')
				swap(a1,b1);
			double e=6.11*(pow(2.718281828,5417.7530*((1/273.16)-(1/(b1+273.16)))));
			double h=0.5555*(e-10.0);
			double humidex = a1+h;
			printf("T %.1lf D %.1lf H %.1lf\n",a1,b1,humidex);
		}
		else if(a=='T'&&b=='H'||a=='H'&&b=='T')
		{
			if(a=='H'&&b=='T')
				swap(a1,b1);
			double dewpoint;
			double h=b1-a1;
			double e=h/0.5555+10.0;
			double x=log(e/6.11)/5417.753;
			dewpoint=1/(1/273.16-x)-273.16;
			printf("T %.1lf D %.1lf H %.1lf\n",a1,dewpoint,b1);
		}
		else // d h
		{
			if(a=='H'&&b=='D')
				swap(a1,b1);
			double e=6.11*pow(2.718281828,5417.7530*((1/273.16)-(1/(a1+273.16))));
			double h=(0.5555)*(e - 10.0);
			double temperature=b1-h;
			printf("T %.1lf D %.1lf H %.1lf\n",temperature,a1,b1);
		}
	}


}

B - Moving Tables

题目大意

两排都是房间,一排两百个房间,上面按奇数,下面按偶数编号,之后房间两两之间要搬桌子,搬桌子期间中间通道全部占用,可同步进行,搬一次10分钟,求最小时间

思路

就把中间通道编号,奇数和偶数的编号调成1-200,之后对区间进行累加,重合次数最多的就是最小时间。注意坑就是,区间不一样从小到大,l,r要判断一下大小。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int box[205];
/*
3
4
10 20
30 40
50 60
70 80
2
1 3
2 200
3
10 100
20 80
30 50
*/
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		memset(box,0,sizeof(box));
		int maxx=0;
		for(int i=1; i<=n; i++)
		{
			int l,r;
			cin>>l>>r;
			if(l%2==1)
				l=l+1;
			if(r%2==1)
				r=r+1;
			l=l/2;
			r=r/2;
			if(l>r)
				swap(l,r);
			for(int j=l; j<=r; j++)
			{
				box[j]++;
				maxx=max(box[j],maxx);
			}
		}
		printf("%d\n",maxx*10);

	}

}

C - Counterfeit Dollar

题意

有12个硬币,现在知道其中有一个假的,已知称三次天平可以找出来假硬币,假硬币有可能轻或重,每次给三组称量结果,求出哪个是硬币,是轻是重。

思路

好丑陋的代码,不懂为啥我写的这么长,思路不太好吧,我的思路就是去暴力枚举每一个假硬币,并且枚举它是轻的假还是重的假,用box数组记录每次天平上各个位置的重量,真硬币就算重量1,假轻硬币就重量0,假重硬币就重量10,最后判断,找出来就行,模拟题,写的是真费劲,OJ还不支持string 用的char还查了一堆函数,费劲,代码能力现在下降严重。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
/*
1
ABCDEF GHIJKL up 
ABC DEF even 
I J down 
*/
int box[20];
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		char a[3][15],b[3][15],c[3][15];
		memset(box,0,sizeof(box));
		for(int i=0; i<3; i++)
		{
			scanf("%s %s %s",a[i],b[i],c[i]);
			strcat(a[i],b[i]);
		}
		for(int i=1; i<=12; i++) // 枚举每个都是假币
		{
			char x='A'+i-1;
			// 假币轻
			int flagt=0;
			int pos,lenn;
			char t[20];
			for(int j=0; j<3; j++)
			{
				memset(box,0,sizeof(box));
				int len=strlen(a[j]);
				for(int k=0; k<len; k++)
				{
					if(a[j][k]!=x)
						box[k]++;
					if(a[j][k]==x)
					{
						pos=k;
						lenn=len;
//						t=c[j];
						strcpy(t,c[j]);
					}
				}
				int box1=0,box2=0;
				for(int k=0; k<len/2; k++)
					box1+=box[k];
				for(int k=len/2; k<len; k++)
					box2+=box[k];
				
				if(strcmp(c[j],"even")==0&&box1==box2) flagt++;
				if(strcmp(c[j],"up")==0&&box1>box2) flagt++;
				if(strcmp(c[j],"down")==0&&box1<box2) flagt++;
//				printf("%d %d %c %d len=%d\n",box1,box2,x,flagt,len);
			}

			//假币重
			if(flagt!=3)
			{
				flagt=0;
				for(int j=0; j<3; j++)
				{
					memset(box,0,sizeof(box));
					int len=strlen(a[j]);
					for(int k=0; k<len; k++)
					{
						if(a[j][k]!=x)
							box[k]++;
						if(a[j][k]==x)
						{
							box[k]+=10;
							pos=k;
							lenn=len;
//							t=c[j];
							strcpy(t,c[j]);
						}
					}
					int box1=0,box2=0;
					for(int k=0; k<len/2; k++)
						box1+=box[k];
					for(int k=len/2; k<len; k++)
						box2+=box[k];
					if(strcmp(c[j],"even")==0&&box1==box2) flagt++;
					if(strcmp(c[j],"up")==0&&box1>box2) flagt++;
					if(strcmp(c[j],"down")==0&&box1<box2) flagt++;
				}
			}
			if(flagt==3)
			{
				if(pos<lenn/2)
				{
					if(strcmp(t,"up")==0)
						printf("%c is the counterfeit coin and it is heavy.\n",x);
					else
						printf("%c is the counterfeit coin and it is light.\n",x);
				}
				else
				{
					if(strcmp(t,"up")==0)
						printf("%c is the counterfeit coin and it is light.\n",x);
					else
						printf("%c is the counterfeit coin and it is heavy.\n",x);
				}
				break;
			}
		}
	}

}

D - Radar Installation

题目大意

雷达部署在x轴,给出半径,陆地在任意位置,现在已知所有陆地位置,要求使用最少雷达覆盖所有陆地。

思路

以每个陆地为圆心画圆,交x轴出现线段,线段长度即为这个陆地所需要的雷达区间,对每个陆地转化为一个线段,将线段按右端点排序,之后从左往右遍历线段,每次呢取端点的最右端作为雷达,下一个线段出现左端点在雷达左右两边的情况,在左边呢就不用管,在右边呢就更新右端点为新的雷达。
这个题,输入格式好奇怪,我觉得是个错题。思路对了,照着别的代码硬改出来。为什么n=0能过?不应该n0&&d0吗?

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

struct node
{
	double l,r;
} a[1005];
int cmp(node a,node b)
{
	return a.r<b.r;
}
int main()
{
	int cnt=0;
	int n;double d;
	while(scanf("%d%lf",&n,&d))
	{
		cnt++;
		if(n==0) break;
		int flag=0;
		for(int i=1; i<=n; i++)
		{
			double x,y;
			scanf("%lf%lf",&x,&y);
//			if(d<y||d<=0)
			if(d<y||d<=0)
			{
				flag=1;
				continue;
			}
			double c=sqrt(1.0*d*d-1.0*y*y);
			a[i].l=(double)x-c;
			a[i].r=(double)x+c;
//			printf("%lf %lf\n",a[i].l,a[i].r);
		}
		if(flag==1)
		{
			printf("Case %d: -1\n",cnt);
			continue;
		}
		sort(a+1,a+1+n,cmp);
		int ans=0;
		double pos=-100000000;
		for(int i=1; i<=n; i++)
		{
			if(pos<a[i].l)
			{
				pos=a[i].r;
				ans++;
			}
		}
		printf("Case %d: %d\n",cnt,ans);
	}
}

E - Truck History

题目大意

给n个卡车,每个卡车的编号由一个七个小写字母的字符串组成,每个卡车的编号唯一,已知一开始只有一辆卡车的编号,一个卡车可以向另一个卡车转换,代价是对应七个位置的不同字母的个数,现在要求出出现所有卡车编号出现的最小代价,最后结果取倒数。

思路

对于每一个卡车都可以当作是一个结点,做一个完全图,卡车两两转换的代价就是边权,求所有卡车出现的最小代价就是最小生成树,因为是点稠密所以选prim。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

int a[2005][2005];
char truck[2005][10];
int n;
int v[2005];
int d[2005];
void prim()
{
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));
	d[1]=0;
	for(int i=1;i<n;i++)
	{
		int x=0;
		for(int j=1;j<=n;j++)
		{
			if(!v[j]&&(x==0||d[j]<d[x])) x=j;
		}
		v[x]=1;
		for(int y=1;y<=n;y++)
			if(!v[y]) d[y]=min(d[y],a[x][y]);
	}

}
int main()
{

	while(scanf("%d",&n)&&n!=0)
	{

		for(int i=1; i<=n; i++)
			scanf("%s",truck[i]);
		for(int i=1; i<=n; i++)
			for(int j=1; j<=n; j++)
			{
				int cnt=0;
				for(int k=0; k<7; k++)
					if(truck[i][k]!=truck[j][k])
						cnt++;
				a[i][j]=cnt;
			}
		prim();
		int ans=0;
		for(int i=2;i<=n;i++)
			ans+=d[i];
		printf("The highest possible quality is 1/%d.\n",ans);
	}


}

F - Wormholes

题意

给n个顶点,m个权值为正的边,w个权值为负的边,现在问图中有没有一个环为负

思路

用简单的bellman-ford做,对边进行n-1轮松弛,在没有负边的情况下,可以得到一个点到所有点的最短路径,如果第n轮还能发现更短的路径,说明存在一个环为负。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
	int u,v,w;
}e[5500];
int dist[1005];
int tot;
void add(int u,int v,int w)
{
	e[++tot].u=u;
	e[tot].v=v;
	e[tot].w=w;	
}

int main()
{
	int f;
	cin>>f;
	while(f--)
	{
		int n,m,w;
		cin>>n>>m>>w;
		memset(dist,0x3f,sizeof(dist));
		dist[1]=0;
		tot=0;
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			cin>>x>>y>>z;
			add(x,y,z);
			add(y,x,z);
		}
		for(int i=1;i<=w;i++)
		{
			int x,y,z;
			cin>>x>>y>>z;
			add(x,y,-z);
		}
		for(int k=1;k<=n-1;k++)
			for(int i=1;i<=tot;i++)
				if(dist[e[i].v]>dist[e[i].u]+e[i].w)
					dist[e[i].v]=dist[e[i].u]+e[i].w;
		int flag=0;
		for(int i=1;i<=tot;i++)
			if(dist[e[i].v]>dist[e[i].u]+e[i].w)
			{
				flag=1;
				break;
			}
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl; 
	}
}

G - Balance

题目大意

一个天平,左右可以放一些砝码,不同的位置会有不同的力矩,给定c个位置,天平中间是0,给g个砝码,砝码的重量各个不同。求一共有多少种方案使得天平平衡。

思路

dp题,设dp[i][j]表示,使用了前i个砝码,目前天平右边减去左边重量的差值为j的方案数,枚举所有砝码,枚举所有重量差值,再枚举所有位置,差值存在负数,范围为 -15 * 20 * 25 到15 * 20 * 25 ,最远力臂15* 最大砝码20* 25最多数量,范围改为 0-15000,默认7500为平衡点。之后转移方案就行。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

int dp[21][15005]; 
//dp[i][j]: 放了前i个物品,砝码右边减去砝码左边重量的差值为j时候的方案数 
int pos[25];
int fama[25];
int main()
{
	int c,g;
	scanf("%d%d",&c,&g);
	for(int i=1;i<=c;i++)
		scanf("%d",&pos[i]);
	for(int i=1;i<=g;i++)
		scanf("%d",&fama[i]);
	dp[0][7500]=1;
	for(int i=1;i<=g;i++)	
		for(int j=0;j<=15000;j++)
		{
			for(int k=1;k<=c;k++)
				if(j+fama[i]*pos[k]<=15000)
					dp[i][j+fama[i]*pos[k]]+=dp[i-1][j];
		}
	printf("%d",dp[g][7500]);	
}

H - Cow Bowling

题目大意

从顶点往下向左或向右,走到最下面,找到一条累加和最大的值。

思路

数字三角形经典题

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

int dp[355][355];
int m[355][355];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
			scanf("%d",&m[i][j]);
	}
	for(int i=1;i<=n;i++)
		dp[n][i]=m[n][i];
	for(int i=n-1;i>=1;i--)
		for(int j=1;j<=i;j++)
		{
			dp[i][j]=m[i][j]+max(dp[i+1][j],dp[i+1][j+1]);
		}
	printf("%d",dp[1][1]);
}

J - Beat the Spread!

简单题,注意非负可以为0

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		if((a+b)%2)
		{
			printf("impossible\n");
			continue;
		}
		int maxx=(a+b)/2;
		int minn=a-maxx;
		if(maxx<0||minn<0)
		{
			printf("impossible\n");
			continue;
		}
		printf("%d %d\n",maxx,minn);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值