2014台州学院ACM集训队寒假练习赛1

A Bridge

只想到一种情况 另外一种情况是参考别人的

2个人为一轮

a b c d

a b 去 a 回 c d 去 b 回(最小的2个去 2个在回来 。。。)

其实还有一种

a b 去 a 回 a c 去 a 回(只是最小的来回)

2中情况要具体分析 不能全是第一种 全是第二种 每2个2个人取小值

这个真不会

语言: C++   用户:614173971  提交时间 : 2014-01-15 16:33:33.0

	
#include <cstdio>
#include <algorithm>
using namespace std;
const __int64 MAX = 100010;
__int64 a[MAX];

int main()
{
	__int64 n;
	__int64 i;
	while(~scanf("%I64d",&n))
	{
		for(i = 1;i <= n; i++)
			scanf("%I64d",&a[i]);
		if(n == 0)
		{
			printf("%0\n");
			continue;
		}
		if(n == 1)
		{
			printf("%I64d\n",a[1]);
			continue;
		}
		sort(a+1,a+n+1);
		__int64 sum = 0;
		for(i = n; i >= 4; i -= 2)
			sum += min(2 * a[1] + a[i] + a[i-1],a[1] + 2 * a[2] + a[i]);
		if(n%2 == 0)
			sum += a[2];
		else			
			sum += a[1] + a[2] + a[3];
		printf("%I64d\n",sum);
	}
	return 0;
}

 

 

B 3-sided dice

这题是看书学习的 据说是经典题 黑书上有讲 转换成点是否在三角形内 三维的叉积 点积

好题

#include <cstring>
#include <cmath>
#include <cstdio>

const double eps = 1e-10;
struct Point3
{
	double x, y, z;
	Point3(double x=0, double y=0, double z=0):x(x),y(y),z(z){}
};
typedef Point3 Vector3;

Vector3 operator + (Vector3 A, Vector3 B)
{
	return Vector3(A.x+B.x, A.y+B.y, A.z+B.z);
}
Vector3 operator - (Vector3 A, Vector3 B)
{
	return Vector3(A.x-B.x, A.y-B.y, A.z-B.z);
}
int dcmp(double x)
{
	if(fabs(x) < eps)
		return 0;
	else
		return x < 0 ? -1 : 1;
}
double Dot(Vector3 A, Vector3 B)//点积 
{
	return A.x*B.x + A.y*B.y + A.z*B.z;
}
double Length(Vector3 A)//向量长度 
{
	return sqrt(Dot(A, A));
}
Vector3 Cross(Vector3 A, Vector3 B)//求叉积 
{
	return Vector3(A.y*B.z - A.z*B.y, A.z*B.x - A.x*B.z, A.x*B.y - A.y*B.x);
}
double Area(Point3 p0, Point3 p1, Point3 p2)
{
	return Length(Cross(p1-p0, p2-p0));
}
bool PointInTri(Point3 p, Point3 p0, Point3 p1, Point3 p2)//判断p是否在三角形内 
{
	double area1 = Area(p, p0, p1);
	double area2 = Area(p, p1, p2);
	double area3 = Area(p, p2, p0);
	if(Area(p0,p1,p2) == 0)//3个点没有成为三角形 线段或者点的情况 
	{
		if(Dot(p0-p, p1-p) < 0)
			return true;
		if(Dot(p1-p, p2-p) < 0)
			return true;
		if(Dot(p2-p, p0-p) < 0)
			return true;
		return false;
	}
	if(dcmp(area1) == 0)//不能在三角形边上 
		return false;
	if(dcmp(area2) == 0)
		return false;
	if(dcmp(area3) == 0)
		return false;
	return dcmp(area1 + area2 + area3 - Area(p0,p1,p2)) == 0;
}

bool ok(Point3 p, Point3 p0, Point3 p1, Point3 p2)//判断p是否在三角形所在的平面上 
{
	Vector3 A = Cross(p1-p0, p2-p0);
	Vector3 B = p-p0;
	return dcmp(Dot(A, B)) == 0; 
}
int main()
{
	double x,y,z;
	while(scanf("%lf %lf %lf",&x,&y,&z),x||y||z)
	{
		Point3 p0(x,y,z);
		scanf("%lf %lf %lf",&x,&y,&z);
		Point3 p1(x,y,z);
		scanf("%lf %lf %lf",&x,&y,&z);
		Point3 p2(x,y,z);
		scanf("%lf %lf %lf",&x,&y,&z);
		Point3 p(x,y,z);
		if(ok(p,p0,p1,p2) && PointInTri(p,p0,p1,p2))
			puts("YES");
		else
			puts("NO");
	}
	
	return 0;
}


 

C Relocation

dijkstra 因为k最多就5个 求出k个超市到所有点的距离 然后枚举起点(除去k个点)途径k个超市 在回来 你们所以需要的条件已经通过dijkstra求出来了

只需枚举求最小值 n*2^k 加上最短路 k*nlogn

	
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define pii pair<int,int> 
#define INF 999999999;
using namespace std;
const int MAX = 10010;

vector <pii> edge[MAX];
int ok[MAX];
int dis[10][MAX];
int ans[10];
int n,m,k;

void dijkstra(int s, int pos)
{
	priority_queue <pii, vector<pii> ,greater<pii> > q;
	bool vis[MAX];
	for(int i = 1;i <= n; i++)
	{
		if(i == s)
			dis[pos][i] = 0;
		else
			dis[pos][i] = INF;
	}
	memset(vis,false,sizeof(vis));
	q.push(make_pair(0,s));
	while(!q.empty())
	{
		pii u = q.top();
		q.pop();
		int x = u.second;
		if(vis[x])
			continue;
		vis[x] = true;
		int len = edge[x].size();
		for(int i = 0; i < len; i++)
		{
			pii v = edge[x][i];
			if(dis[pos][v.second] > dis[pos][x] + v.first)
			{
				dis[pos][v.second] = dis[pos][x] + v.first;
				q.push(make_pair(dis[pos][v.second],v.second));
			}
		}
	}
}
				
int main()
{
	int i,j;
	int u,v,w;
	int sum = INF;
	scanf("%d %d %d",&n,&m,&k);
	for(i = 1;i <= k; i++)
	{
		scanf("%d",&j);
		ans[i] = j;
		ok[j] = i;
	}
	for(i = 1;i <= m; i++)
	{
		scanf("%d %d %d",&u,&v,&w);
		edge[u].push_back(make_pair(w,v));
		edge[v].push_back(make_pair(w,u));
	}
	for(i = 1; i <= k; i++)
		dijkstra(ans[i],i);
	for(i = 1;i <= n; i++)
	{
		if(ok[i])
			continue;
		
		sort(ans+1,ans+1+k);
		do
		{
			int cnt = 0;
			for(j = 1;j <= k; j++)
			{
				if(j == 1)
					cnt += dis[ok[ans[j]]][i];
				else if(j == k)
					cnt += dis[ok[ans[j]]][i] + dis[ok[ans[j]]][ans[j-1]];
				else 
					cnt += dis[ok[ans[j]]][ans[j-1]];
			}
			if(sum > cnt)
				sum = cnt;
			//printf("%d\n",cnt);
		}while(next_permutation(ans+1,ans+k+1));
	}
	printf("%d\n",sum);
	return 0;
}


 

D Treasure Hunt

找出循环节就行了 自己就是速度太慢了 简单题也写了半天

#include <cstdio>
#include <cstring>
#include <cstdio>
using namespace std;
struct node
{
	int u;
	int v;
}a[220][22];
int b[100000];
int mp[220][22];
int main()
{
	int n,m,t,s;
	int i,j,u,v;
	int cnt;
	while(scanf("%d %d %d %d",&m,&t,&s,&n)!=EOF)
	{
		cnt = 1;
		memset(mp,0,sizeof(mp));
		for(i = 1;i <= m; i++)
		{
			for(j = 1;j <= t; j++)
			{
				scanf("%d %d",&u,&v);
				a[i][j].u = v;
				a[i][j].v = u;
			}
		}
		u = s;
		v = 1;
		mp[s][1] = cnt;
		b[cnt++] = s;
		while(1)
		{
			int uu = u;
			int vv = v;
			
			u = a[uu][vv].u;
			v = a[uu][vv].v;
			//printf("  %d %d\n",u,v);
			if(cnt-1 == n)
			{
				printf("%d\n",b[cnt-1]);
				break;
			}
			if(mp[u][v])
			{
				int k = cnt - mp[u][v];
				int nn = (n - mp[u][v] + 1) % k;
				if(nn == 0)
					nn = k;
				printf("%d\n",b[mp[u][v] - 1 + nn]);
				//printf("%d\n",k);
				break;
			}
			else
			{
				mp[u][v] = cnt;
				b[cnt++] = u;
			}
		}			
	}
	return 0;
}


 

E The End of Corruption

我直接用了优先队列 1A 是不是数据水了啊 5s 用了340ms

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

int main()
{
	int n,m;
	int i,x;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		priority_queue <int> q;
		for(i = 1;i <= n + m; i++)
		{
			scanf("%d",&x);
			if(x == -1)
			{
				printf("%d\n",q.top());
				q.pop();
			}
			else
				q.push(x);
		}
	}
	return 0;
}

F What is the Rank?

一看是二分 开始错了2次 犯傻了 

每次二分到那个位置把那个数插进去 数组很难能实现 10秒我就乱搞了 用vector insert 结果对了

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAX = 45010;
int a[MAX];
vector <int> dp;
int pos[MAX];
int main()
{
	int n;
	int i,j,l,r,m,len;
	scanf("%d",&n);
	for(i = 0;i < n; i++)
		scanf("%d",&a[i]);
	dp.push_back(a[0]);
	pos[0] = 0;
	len = 0;
	for(i = 1;i < n; i++)
	{
		l = 0;
		r = dp.size() - 1;
		while(l <= r)
		{
			m = (l + r) >> 1;
			if(a[i] < dp[m])
				l = m + 1;
			else
				r = m - 1;
		}
		dp.insert(dp.begin()+l,a[i]);
		pos[i] = l;
	}
	for(i = 0;i < n; i++)
		printf("%d\n",pos[i]+1);
	return 0;
}


 

G Critical Intersections

一看题意 发现是割点 书上看到过 学了下 一下就懂了 裸的应用 可以看一下白皮书

一个dfs算法解决

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int MAX = 310;
vector <int> G[MAX];
int pre[MAX];
int low[MAX];
bool iscnt[MAX];
int n,m;
int cnt = 0;//时间戳 
int dfs(int u,int fa)
{
	int lowu = pre[u] = ++cnt;
	int child = 0;//子节点数
	for(int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if(!pre[v])
		{
			child++;
			int lowv = dfs(v,u);
			lowu = min(lowu,lowv);
			if(lowv >= pre[u])
			 iscnt[u] = true;
		}
		else if(pre[v] < pre[u] && v != fa)
		{
			lowu = min(lowu,pre[v]);
		}
	}
	if(fa < 0 && child == 1)
		iscnt[u] = false;
	low[u] = lowu;
	return lowu;
}
int main()
{
	int i,u,v;
	scanf("%d %d",&n,&m);
	for(i = 1;i <= m; i++)
	{
		scanf("%d %d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,-1);
	int sum = 0;
	for(i = 1;i <= n; i++)
		if(iscnt[i])
			sum++;
	printf("%d\n",sum);
	return 0;
}

 

H Word Hopping

记忆化搜索 就滑雪那样的 没有了4个方向 更简单了

题意看清就行

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char a[120][20];
int dp[120];
int vis[120];
int n;
bool ok1(char *s1,char *s2)
{
	int i,j;
	int cnt = 0;
	int len = strlen(s1);
	for(i = 0;i < len; i++)
	{
		if(s1[i] > s2[i])
			return false;
		if(s1[i] < s2[i])
		{
			for(j = i + 1;j < len; j++)
				if(s2[i] == s1[j])
					break;
			if(j == len)
				return false;
		}
		if(s1[i] != s2[i])
			cnt++;
	}
	if(cnt != 1)
		return false;
	return true;
}

bool ok2(char *s1,char *s2)
{
	int i,j;
	int cnt = 0;
	int len = strlen(s2);
	for(i = 0;i < len; i++)
	{
		if(s1[i] != s2[i])
			break;
	}
	
	if(i == len)
		return true;
	for(j = i,i = j + 1; j < len; i++,j++)
		if(s1[i] != s2[j])
			return false;
	return true;
}
bool check(char *s1,char *s2)
{
	if(strlen(s1) < strlen(s2))
		return false;
	else if(strlen(s1) == strlen(s2))
	{
		if(ok1(s1,s2))
			return true;
	}
	else if(strlen(s1) - 1 == strlen(s2))
	{
		if(ok2(s1,s2))
			return true;
	}
	return false;
}

int dfs(int u)
{
	if(vis[u])
		return dp[u];
	int i;
	int max = 0;
	for(i = 1;i <= n; i++)
	{
		if(u == i)
			continue;
		if(!check(a[u],a[i]))
			continue;
		int temp = dfs(i);
		if(max < temp)
			max = temp;
	}
	dp[u] = max + 1;
	vis[u] = true;
	return dp[u];
}
int main()
{
	int i,j;
	while(scanf("%d",&n)!=EOF)
	{
		for(i = 1;i <= n; i++)
			scanf("%s",a[i]);
		memset(dp,0,sizeof(dp));
		memset(vis,false,sizeof(vis));
		int max = 0;
		for(i = 1;i <= n; i++)
		{
			int temp = dfs(i);
			if(max < temp)
				max = temp;
		}
		printf("%d\n",max);
	}
	return 0;
}

I Siruseri Metro System

 不会啊 求告知

 

J Equal Gifts

二维01背包 一不小心A了 一维也可以的

#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
	int u;
	int v;
}a[200];
bool dp[2][100000];
bool map[2][100000];
int main()
{
	int n,i,j,k;
	int m = 0;
	int sum = 0;
	while(scanf("%d",&n)!=EOF)
	{
		memset(dp,false,sizeof(dp));
		memset(map,false,sizeof(map));
		sum = 0;
		for(i = 1;i <= n; i++)
		{
			scanf("%d %d",&a[i].u,&a[i].v);
			sum += a[i].u + a[i].v;
		}
		map[1][0] = map[0][0] = true;
		for(i = 1;i <= n; i++)
		{
			memcpy(dp,map,sizeof(map));
			memset(map,false,sizeof(map));
			
			for(j = m; j >= 0;j--)
			{
				if(dp[0][j])
				{
					map[0][j+a[i].u] = true;
					map[0][j+a[i].v] = true;
					m = max(m,j+a[i].u);
					m = max(m,j+a[i].v);
				}
				if(dp[1][j])
				{
					map[1][j+a[i].u] = true;
					map[1][j+a[i].v] = true;
					m = max(m,j+a[i].u);
					m = max(m,j+a[i].v);
				}
			}
		}
		for(i = sum/2 ;i >= 1; i--)
		{
			if(map[0][i] || map[1][i])
				break;
		}
		printf("%d\n",sum-2*i);
	}
	return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值