TopCoder SRM 573

div.1

T2

题意

给定一个50个点的图, 每个点有一个高度, 从一个点u到另一个点v的条件是u, v直接相连, 并且h[u] >= h[v],每个点的高度可以改变代价为改变前后高度差的绝对值, 求从点0到点n - 1的最小代价。

思路

定义dp[u][h]表示顶点u高度为h时最小代价由于最优方案中每个点的高度可以是这50个点的起始高度所以可以将高度离散化一下, 由于转移代价的特殊性, 我们可以看成是一个50 * 50个点的最短路问题

#include <bits/stdc++.h>
using namespace std;
const long long inf= 1ll<<60 ;
queue<pair<int,int>> q;
long long d[100][100];
int vis[100][100],t[100010];
class SkiResorts {
public:
    long long minCost( vector <string> road, vector <int> altitude );
};
long long SkiResorts::minCost(vector <string> a, vector <int> h) {
	int i,n,j,u,v;
	long long ans=inf;
	n=h.size();
	memset(vis,0,sizeof(vis));
	for(i=0;i<n;i++) t[i]=h[i];
	sort(t,t+n);
	for(i=0;i<52;i++)
		fill(d[i],d[i]+52,inf);

	for(i=0;i<n;i++)
	{
		d[0][i]=abs(t[i]-h[0]);
		q.push(make_pair(0,i));
		vis[0][i]=1;
	}
	
	while(!q.empty())
	{
		pair<int,int> w;
		w=q.front();
		q.pop();
		vis[w.first][w.second]=0;
		u=w.first;
		for(v=0;v<n;v++)
			if(a[u][v]!='N')
				for(j=w.second;j>=0;j--)
					if(d[v][j]>d[u][w.second]+abs(t[j]-h[v]))
					{
						d[v][j]=d[u][w.second]+abs(t[j]-h[v]);
						if(vis[v][j]==0) q.push(make_pair(v,j));
					}
	}
	
	for(i=0;i<n;i++)
		ans=min(ans,d[n-1][i]);
	if(ans==inf) return -1;
	return ans;
}

div.2

T3

题意

给一个矩阵,某些点里面有狼,现在这些狼要在m次移动内都聚合到同一个点上,每次移动只能移动到当前格子的四个相邻的格子内,问有多少种方案让这些狼都移动到相同的点上?

思路

首先,dp[k][i][j]表示到[i,j]格子内,经过k次移动,有多少种方案,该点的上一个状态一定是相邻的四个点,那么把那四个相邻点的方案算出来,这个点的方案自然也就知道了
鉴于这个平面的范围很小,可以暴力枚举终点!利用乘法原理就能得到方案数。
那么所有终点的方案数加起来就可以了。

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int d[60][110][110];
class WolfPackDivTwo {
public:
    int calc( vector <int> x, vector <int> y, int m );
};
int WolfPackDivTwo::calc(vector <int> a, vector <int> b, int m) {
	int i,j,x,y,xx,yy,n;
	long long ans=0,t;
	d[0][50][50]=1;
	n=a.size();
	for(j=0;j<m;j++)
		for(x=1;x<100;x++)
			for(y=1;y<100;y++)
				for(i=0;i<4;i++)
				{
					xx=x+dx[i];
					yy=y+dy[i];
					d[j+1][xx][yy]=(d[j+1][xx][yy]+d[j][x][y])%mod;
				}
	for(y=-50;y<=100;y++)
		for(x=-50;x<=100;x++)
		{
			t=1;
			for(i=0;i<n;i++)
			{
				xx=abs(x-a[i]);
				yy=abs(y-b[i]);
				if(xx+yy>m)
				{
					t=0;
					break;
				}
				t=(t*d[m][50+yy][50+xx])%mod;
			}
			ans=(ans+t)%mod;
		}
	return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值