HDU 4284 —— Travel 状压dp|DFS+Floyd

http://acm.hdu.edu.cn/showproblem.php?pid=4284


题意:n个城市,m条边,以及初始的钱数;下面m行给出每条边的u、v以及花费;然后是h个城市,每行给出城市编号、能赚的钱、买证的钱;PP要去这h个城市打工并且返回1城市(起点是1),要在该城市打工就得先买证,问PP能否成功;



DFS+Floyd

#include<stdio.h>
#include<string.h>
#define inf 1e9
const int maxn = 110;
int map[maxn][maxn];
bool vis[maxn];
int n, m, init, h;
bool flag;

struct node
{
	int id, c, d;
}nod[maxn];

void Init()
{
	flag = false;
	memset(vis, false, sizeof vis);
	for(int i = 1;i<=n;i++)
	{
		for(int j = 1;j<=n;j++)
		{
			if(i == j)
			map[i][j] = 0;
			else
			map[i][j] = inf;
		}
	}
}

void dfs(int u, int num)
{
	if(num == h)
	{
		if(init - map[u][1] >= 0)
		{
			flag = true;
			return;
		}
	}
	if(flag)	return;
	for(int i = 1;i<=h;i++)
	{
		int v = nod[i].id;
		if(map[u][v] != inf && (init-map[u][v])>=nod[i].d && !vis[v])
		{
			vis[v] = true;
			init += (nod[i].c - nod[i].d - map[u][v]);
			dfs(v, num+1);
			vis[v] = false;
			init -= (nod[i].c - nod[i].d - map[u][v]);
		}
	}
}

void Floyd()
{
	for(int k = 1;k<=n;k++)
	{
		for(int i = 1;i<=n;i++)
		{
			for(int j = 1;j<=n;j++)
			{
				if(map[i][j] > map[i][k]+map[k][j])
				map[i][j] = map[i][k]+map[k][j];
			}
		}
	}
}

int main()
{
	int cas;
	scanf("%d", &cas);
	while(cas--)
	{
		scanf("%d%d%d", &n, &m, &init);
		Init();
		while(m--)
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			if(u == v)	continue;
			if(map[u][v] > w)
			map[u][v] = map[v][u] = w;
		}
		Floyd();
		scanf("%d", &h);
		for(int i = 1;i<=h;i++)
			scanf("%d%d%d", &nod[i].id, &nod[i].c, &nod[i].d);
		dfs(1, 0);
		if(flag)	printf("YES\n");
		else	printf("NO\n");
	}
	return 0;
}



状压DP

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define inf 1e9
using namespace std;
const int maxn = 110;
int dp[1<<16][20];
int n, m, h, money;
int map[maxn][maxn];

struct Node
{
	int id, ci, di;
}node[20];

void init()
{
	memset(dp, -1, sizeof dp);
	for(int i = 1;i<=n;i++)
	{
		for(int j = 1;j<=n;j++)
		{
			if(i == j)
			map[i][j] = 0;
			else
			map[i][j] = inf;
		}
	}
}

void Floyd()
{
	for(int k = 1;k<=n;k++)
	{
		for(int i = 1;i<=n;i++)
		{
			for(int j = 1;j<=n;j++)
			map[i][j] = min(map[i][j], map[i][k]+map[k][j]);
		}
	}
}

int main()
{
	int cas;
	scanf("%d", &cas);
	while(cas--)
	{
		scanf("%d%d%d", &n, &m, &money);
		init();
		while(m--)
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			if(map[u][v] > w)
			map[u][v] = map[v][u] = w;
		}
		Floyd();
		scanf("%d", &h);
		for(int i = 0;i<h;i++)
		{
			scanf("%d%d%d", &node[i].id, &node[i].ci, &node[i].di);
			int v = node[i].id;
			int val = money - map[1][v] - node[i].di;
			if(val >= 0)
				dp[1<<i][i] = val + node[i].ci;
		}
		int st = 1<<h;
		for(int i = 1;i<st;i++)
		{
			for(int j = 0;j<h;j++)
			{
				if(dp[i][j] == -1)	continue;
				for(int k = 0;k<h;k++)
				{
					if(i & (1<<k))	continue;
					int val = dp[i][j] - map[node[j].id][node[k].id] - node[k].di;
					if(val >= 0)
						dp[i|(1<<k)][k] = max(dp[i|(1<<k)][k], val+node[k].ci);
				}
			}
		}
		int ans = -1;
		for(int i = 0;i<h;i++)
		{
			ans = max(ans, dp[st-1][i] - map[node[i].id][1]);
		}
		if(ans != -1)	printf("YES\n");
		else	printf("NO\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值