上海邀请赛

本文详细解析了2014年上海邀请赛中的六道题目,包括AGamewithPearls、SeamCarving、Battleships等,涵盖了贪心算法、动态规划、二分图匹配等多种解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2014-上海邀请赛

A Game with Pearls 

传送门:hdu 5090

给定一个长度为n的数组,可以对任意一个数增加k的倍数,问能否通过调换位置,增数来使得整个数组构成一个1~n的序列

贪心,对k取模分组,因为加k取模不会变,所以首先判断对应组内的个数是否满足最终序列需要的个数,然后从小到大分别对各组内进行判断


/******************************************************
 * File Name:   1001.cpp
 * Author:      kojimai
 * Create Time: 2014年11月02日 星期日 12时47分52秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
#define FFF 105
vector<int> p[FFF];
int a[FFF];
int main()
{
	int keng;
	scanf("%d",&keng);
	while(keng--)
	{
		int n,k;
		cin>>n>>k;
		for(int i = 0;i < n;i++)
			cin>>a[i];
		sort(a,a+n);
		for(int i = 0;i < k;i++)
		{
			p[i].clear();
		}
		for(int i = 0;i < n;i++)
		{
			int t = a[i]%k;
			p[t].push_back(a[i]);
		}
		bool flag = true;
		for(int i = 0;i < k && flag;i++)
		{
			int cnt = n / k;
			if(i && i <= n % k)
				cnt++;
			if(cnt != p[i].size())
				flag= false;
		}
		if(flag)
		for(int i = 1;i < n&&flag;i++)
		{
			int t = i % k;
			if(p[t][0]<=i)
			{
				p[t].erase(p[t].begin());
			}
			else
				flag = false;
		}
		if(flag)
			printf("Jerry\n");
		else
			printf("Tom\n");
	}
	return 0;
}


C Seam Carving 

传送门:hdu 5092

题意比较绕,理解了题意就好做了,从上到下找一条路径,使得路径上的值最小,要求相邻行之间选到的点左右距离值不大大于1

dp类似数塔,求最小统计路径即可

P.S.上海我们队最后一小时就卡在上面了,理解了题意就是敲不出来,做重现顺利过,简直无情.....

/******************************************************
 * File Name:   1003.cpp
 * Author:      kojimai
 * Create Time: 2014年11月02日 星期日 14时25分57秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 105
long long a[FFF][FFF],dp[FFF][FFF];
int road[FFF][FFF];
int main()
{
	int keng,Case = 1;
	cin>>keng;
	while(keng--)
	{
		int n,m;
		cin>>n>>m;
		for(int i = 1;i <= n;i++)
		{
			for(int j = 1;j <= m;j++)
			{
				cin>>a[i][j];
			}
		}
		memset(dp,0,sizeof(dp));
		for(int i = 1;i <= m;i++)
		{
			dp[n][i] = a[n][i];
			road[n][i] = -1;
		}
		for(int i = n - 1;i >= 1;i--)
		{
			for(int j = m;j >= 1;j--)
			{
				if(j < m)
				{
					dp[i][j] = (dp[i+1][j+1] + a[i][j]);
					road[i][j] = j+1;
					if(dp[i+1][j]<dp[i+1][j+1])
					{
						road[i][j] = j;
						dp[i][j] = dp[i+1][j]+a[i][j];
					}
				}
				else
				{
					dp[i][j] = dp[i+1][j] +a[i][j];
					road[i][j] = j;
				}
				if(j>1)
				{
					if(dp[i][j]>(dp[i+1][j-1]+a[i][j]))
					{
						road[i][j] = j-1;
						dp[i][j] = dp[i+1][j-1]+a[i][j];
					}
				}
			}
		}
		long long ans = dp[1][m];
		int s = m;
		for(int i = m - 1;i >= 1;i--)
		{
			if(dp[1][i] < ans)
			{
				ans = dp[1][i];
				s = i;
			}
		}
		printf("Case %d\n%d",Case++,s);
		int cnt = 1;
		while(road[cnt][s] != -1)
		{
			s = road[cnt++][s];
			cout<<' '<<s;
		}
		cout<<endl;
	}
	return 0;
}

D Battle ships 

传送门:hdu 5093

给定一张图,在*位置可以放点,O表示不可放点但点之间可以通过该点相连,#表示可以隔断点问最多放多少个点,使得两两之间不可达

二分图匹配,对每个点进行拆点,分行与列对点编号,同一行或同一列中,中间有#则在行或者列上,该点拆成多个点,这样拆完点之后得到一张二分图进行一次二分匹配即可

/******************************************************
 * File Name:   1004.cpp
 * Author:      kojimai
 * Create Time: 2014年11月02日 星期日 13时12分13秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 55
char s[FFF][FFF];
int hang[FFF][FFF],lie[FFF][FFF];
#define FF 1300
int match[FF],cntx,cnty;
bool mm[FF][FF],vis[FF];
bool dfs(int now)
{
	for(int i = 0;i < cnty;i++)
	{
		if(mm[now][i]&&!vis[i])
		{
			vis[i] = true;
			if(match[i] == -1 || dfs(match[i]))
			{
				match[i] = now;
				return true;
			}
		}
	}
	return false;
}
void printhang()
{
	for(int i = 0;i < 4;i++)
	{
		for(int j = 0;j < 4;j++)
			cout<<hang[i][j]<<' ';
		cout<<endl;
	}
}
void printlie()
{
	for(int i = 0;i < 4;i++)
	{
		for(int j = 0;j < 4;j++)
			cout<<lie[i][j]<<' ';
		cout<<endl;
	}
}
int main()
{
	int keng;
	cin>>keng;
	while(keng--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i = 0;i < n;i++)
			cin>>s[i];
		cntx = cnty = 0;
		bool flag = false;
		memset(hang,-1,sizeof(hang));
		memset(lie,-1,sizeof(lie));
		for(int i = 0;i < n;i++)
		{
			for(int j = 0;j < m;j++)
			{
				if(s[i][j] == '*')
				{
					hang[i][j] = cntx;
					flag = true;
				}
				else if(s[i][j] == '#')
				{
					if(flag == true)
					{
						flag = false;
						cntx++;
					}
				}
			}	
			if(flag)
			{
				flag = false;
				cntx++;
			}
		}
		//在行上拆点
		//printhang();
		flag = false;
		for(int i = 0;i < m;i++)
		{
			for(int j = 0;j < n;j++)
			{
				if(s[j][i] == '*')
				{
					lie[j][i] = cnty;
					flag = true;
				}
				else if(s[j][i] == '#')
				{
					if(flag)
					{
						flag = false;
						cnty++;
					}
				}
			}
			if(flag)
			{
				flag = false;
				cnty++;
			}
		}
		//在列上拆点
		//printlie();
		//cout<<" cntx = "<<cntx<<" cnty = "<<cnty<<endl;
		memset(mm,false,sizeof(mm));
		for(int i = 0;i < n;i++)
		{
			for(int j = 0;j < m;j++)
			{
				if(s[i][j] == '*')
				{
					mm[hang[i][j]][lie[i][j]] = true;
				}
			}
		}
		//for(int i = 0;i < cntx;i++)
		//{
		//	for(int j = 0;j < cnty;j++)
		//		cout<<mm[i][j]<<' ';
		//	cout<<endl;
		//}
		memset(match,-1,sizeof(match));
		int ans = 0;
		for(int i = 0;i < cntx;i++)
		{
			memset(vis,false,sizeof(vis));
			if(dfs(i))
				ans++;
		}
		//答案即为最大匹配数
		cout<<ans<<endl;
	}
	return 0;
}

F  Linearization of the kernel functions in SVM 

传送门:hdu 5095

签到题,注意各种边界条件处理即可

/******************************************************
 * File Name:   1006.cpp
 * Author:      kojimai
 * Create Time: 2014年11月02日 星期日 13时39分25秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
bool first;
void printnum(int x)
{
	if(first)
	{
		first = false;
		if(x>0)
		{
			if(x == 1)
				return;
			else
				cout<<x;
		}
		else
		{
			if(x == -1)
				cout<<'-';
			else
				cout<<x;
		}
	}
	else
	{
		if(x>0)
		{
			if(x == 1)
				cout<<'+';
			else
				cout<<'+'<<x;
		}
		else
		{
			if(x == -1)
				cout<<'-';
			else
				cout<<x;
		}
	}
	return;
}
void printp(int x)
{
	if(x == 0)
		return;
	printnum(x);
	cout<<'p';
}
void printq(int x)
{
	if(x == 0)
		return;
	printnum(x);
	cout<<'q';
}
void printr(int x)
{
	if(x == 0)
		return;
	printnum(x);
	cout<<'r';
}
void printu(int x)
{
	if(x == 0)
		return;
	printnum(x);
	cout<<'u';
}
void printv(int x)
{
	if(x == 0)
		return;
	printnum(x);
	cout<<'v';
}
void printw(int x)
{
	if(x == 0)
		return;
	printnum(x);
	cout<<'w';
}
void printx(int x)
{
	if(x == 0)return;
	printnum(x);
	cout<<'x';
}
void printy(int x)
{
	if(x == 0)return;
	printnum(x);
	cout<<'y';
}
void printz(int x)
{
	if(x == 0)return;
	printnum(x);
	cout<<'z';
}
int main()
{
	int keng;
	cin>>keng;
	while(keng--)
	{
		int p,q,r,u,v,w,x,y,z,j;
		cin>>p>>q>>r>>u>>v>>w>>x>>y>>z>>j;
		first = true;
		printp(p);
		printq(q);
		printr(r);
		printu(u);
		printv(v);
		printw(w);
		printx(x);
		printy(y);
		printz(z);
		if(j)
		{
			if(!first&&j>0)
				cout<<'+'<<j;
			else
				cout<<j;
			first = false;
		}
		if(first)
			cout<<0<<endl;
		cout<<endl;
	}
	return 0;
}

J Comparison of Android versions

传送门:hdu 5099

水题,比较大小就好,一个注意点,分支相同时,在时间比较上才需要考虑最后一个字母

/******************************************************
 * File Name:   1010.cpp
 * Author:      kojimai
 * Create Time: 2014年11月02日 星期日 14时09分47秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
char s1[10],s2[10];
int main()
{
	int keng,Case =1;
	cin>>keng;
	while(keng--)
	{
		int num1,num2;
		cin>>s1>>s2;
		if(s1[0] == s2[0])
		{
			num1 =0 ;
		}
		else if(s1[0] > s2[0])
			num1 = 1;
		else
			num1 = -1;
		if(s1[2] < s2[2])
			num2 = -1;
		else if(s1[2] > s2[2])
			num2 = 1;
		else
		{
			int tmp1 = (s1[3]-'0')*10+s1[4]-'0';
			int tmp2 = (s2[3]-'0')*10+s2[4]-'0';
			if(tmp1>tmp2)
				num2 = 1;
			else if(tmp1<tmp2)
				num2 = -1;
			else 
			{
				num2 = 0;
			}
		}
		if(num2 == 0 && s1[1] == s2[1])
		{
			if(s1[5]>s2[5])
			{
				num2 = 1;
			}
			else if(s1[5]<s2[5])
				num2 = -1;
		}
		printf("Case %d: ",Case++);
		if(num1==1)
			cout<<'>';
		else if(num1 == 0)
			cout<<'=';
		else
			cout<<'<';
		cout<<' ';
		if(num2==1)
			cout<<'>';
		else if(num2==-1)
			cout<<'<';
		else
			cout<<'=';
		cout<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值