HDU--4784 Dinner Coming Soon DP+BFS

题意很长很变态。一个人要到他男朋友家,他最初有R元以及T分钟的时间来赶到他男朋友家。有N个房子M条道路,每条道路有需要消耗的时间以及过路费,同时还要顺路做食盐生意,起初身上没有食盐,最多带B袋盐,每到达一个地方有三种操作可以选择:1.售出一袋食盐;2:购买一袋食盐;3:什么都不做。然后你以为结束了?不!它还存在平行宇宙,在一个城市可以选择穿越平行宇宙到达另一个宇宙的这个城市,不同宇宙的食盐价格不同但是过路费和道路需要的时间是相同的,而且由于他是穿越党,他不能在别的宇宙回到自己家或者男朋友家,求最后能否到达他男朋友家以及最多能有多少钱。

BFS+DP,因为时间是不可逆的,所以每次按照时间的先后来处理状态,因此需要用优先队列来处理。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <iomanip>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=111;
const int maxm=222;
struct Edge//邻接表
{
	int v;
	int tim;//时间花费
	int cost;//金钱花费
	int next;
};
struct Node
{
	int u,times,k,b;
	bool operator < (const Node &a) const
	{
		return times>a.times;
	}
};
Edge edges[maxm<<1];
int head[maxn];
int num=-1;;
int n,m,B,K,R,T;
int dp[maxn][210][7][7];
int inqueue[maxn][210][7][7];
int price[7][maxn];
void addEdge(int u,int v,int tim,int cost)
{
	num++;
	edges[num].v=v;
	edges[num].tim=tim;
	edges[num].cost=cost;
	edges[num].next=head[u];
	head[u]=num;
}
int bfs()
{
	int flag=0;
	memset(dp,0,sizeof(dp));
	memset(inqueue,0,sizeof(inqueue));
	dp[1][0][0][0]=R;//初始金钱
	Node node,tmp;
	priority_queue<Node>q;//优先队列,按时间处理
	node.u=1;//起始状态
	node.times=0;
	node.k=0;
	node.b=0;
	inqueue[1][0][0][0]=1;
	q.push(node);
	while(!q.empty())
	{
		node=q.top();
		q.pop();
		if(node.times>T)//当队里的元素的时间都大于T就无需处理了
		{
			break;
		}
		int u=node.u;
		if(u==n)
		{
			//cout<<node.times<<endl;
			continue;
		}
		for(int i=head[u];i!=-1;i=edges[i].next)//走到下一个城市
		{
			int v=edges[i].v;
			int cost,tim;
			cost=dp[u][node.times][node.k][node.b]-edges[i].cost;//剩下的金钱
			tim=node.times+edges[i].tim;//时间
			if(tim>T||cost<0)//剪枝
			{
				continue;
			}
			if(v==n&&node.k!=0)//只能在0宇宙到达第N个城市
			{
				continue;
			}
			if(v==n)//成功到达
			{
				flag=1;
			}
			tmp.u=v;
			tmp.times=tim;
			tmp.k=node.k;
			if(u!=1&&u!=n)
			{
				if(node.b+1<=B&&cost-price[node.k][u]>dp[v][tim][node.k][node.b+1])//买一袋盐
				{
					dp[v][tim][node.k][node.b+1]=cost-price[node.k][u];
					tmp.b=node.b+1;
					if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
					{
						q.push(tmp);
						inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
					}
				}
				if(node.b>0&&cost+price[node.k][u]>dp[v][tim][node.k][node.b-1])//卖一袋盐
				{
					dp[v][tim][node.k][node.b-1]=cost+price[node.k][u];
					tmp.b=node.b-1;
					if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
					{
						q.push(tmp);
						inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
					}
				}
			}
			if(cost>dp[v][tim][node.k][node.b])//不买盐
			{
				dp[v][tim][node.k][node.b]=cost;
				tmp.b=node.b;
				if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
				{
					q.push(tmp);
					inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
				}
			}
		}
		if(u!=1&&u!=n)//穿越到下一个宇宙的这个城市
		{
			int cost=dp[u][node.times][node.k][node.b];//金钱不变
			tmp.u=u;
			tmp.k=(node.k+1)%K;
			tmp.times=node.times+1;//看广告时间+1
			if(tmp.times>T)
			{
				continue;
			}
			if(node.b+1<=B&&cost-price[node.k][u]>dp[u][tmp.times][tmp.k][node.b+1])//在这个宇宙的这个城市买盐
        	{
                dp[u][tmp.times][tmp.k][node.b+1]=cost-price[node.k][u];
                tmp.b=node.b+1;
                if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
                {
					q.push(tmp);
					inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
				}
            }
            if(node.b>0&&cost+price[node.k][u]>dp[u][tmp.times][tmp.k][node.b-1])//卖一袋盐
            {
                dp[u][tmp.times][tmp.k][node.b-1]=cost+price[node.k][u];
                tmp.b=node.b-1;
                if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
                {
					q.push(tmp);
					inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
				}
            }
            tmp.b=node.b;
            if(cost>dp[u][tmp.times][tmp.k][tmp.b])//不做操作
            {
                dp[u][tmp.times][tmp.k][tmp.b]=cost;
                if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
                {
					q.push(tmp);
					inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
				}
            }
		}
	}
	if(!flag)
	{
		return -1;//不能到达
	}
	int ans=0;
	for(int i=0;i<=T;i++)
	{
		for(int j=0;j<=B;j++)
		{
			ans=max(ans,dp[n][i][0][j]);//可以到达,在可以到的的情况中选取钱最多的
		}
	}
	return ans;
}
int main()
{
	int t;
	int s=1;
	int u,v,tim,cost;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d%d%d%d",&n,&m,&B,&K,&R,&T);//城市数目,道路数目,食盐上限,宇宙个数,初始金钱,时间上限
		memset(head,-1,sizeof(head));
		num=-1;
		for(int i=0;i<K;i++)
		{
			for(int j=1;j<=n;j++)
			{
				scanf("%d",&price[i][j]);//食盐在每个宇宙每个城市的价格
			}
		}
		for(int i=0;i<m;i++)
		{
			scanf("%d%d%d%d",&u,&v,&tim,&cost);//每条路的起点,终点,时间,花费
			addEdge(u,v,tim,cost);
		}
		int ans;
		ans=bfs();
		printf("Case #%d: ",s++);
		if(ans!=-1)
		{
			printf("%d\n",ans);
		}
		else
		{
			printf("Forever Alone\n");
		}
	}
	return 0;
}

HDU--4784 Dinner Coming Soon DP+BFS

时间: 2024-08-27 11:25:05

HDU--4784 Dinner Coming Soon DP+BFS的相关文章

(BFS)HDU 4784 Dinner Coming Soon

Coach Pang loves his boyfriend Uncle Yang very much. Today is Uncle Yang's birthday, Coach Pang wants to have a romantic candlelit dinner at Uncle Yang's house and he has to arrive there in T minutes.  There are N houses in their city numbered from 1

HDU 3001 Travelling (状压DP + BFS)

题意:有一个人要去旅游,他想要逛遍所有的城市,但是同一个城市又不想逛超过2次.现在给出城市之间的来往路费,他可以选择任意一个点为起点. 问逛遍所有城市的最低路费是多少. 析:用三进制表示每个城市的访问次数,然后 bfs 进行遍历,不过要注意这个题卡内存,必须要去年一些无用的状态,要不然会超内存的,还不能枚举每个城市, 这样可能会超时的,可以直接把所有的城市放进去,直接进行遍历.一个比较经典的题目. 代码如下: #pragma comment(linker, "/STACK:1024000000,

hdu 3681 二分+状态压缩dp+bfs

题意就不用多说了,开始想直接bfs+二分简化下做试试   果断超时,然后不得不用状态压缩dp(其实一开始就想这样做的,15个点   每个点都能走多次   绝逼状态压缩dp) 先bfs跑每个关键点之间的做短路径    再二分起点的能量值               状态压缩dp来判断     不说了    AC吧!!!!! #include<stdio.h> #include<string.h> #include<queue> #include<iostream&g

hdu 3247 AC自动+状压dp+bfs处理

Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)Total Submission(s): 2382    Accepted Submission(s): 750 Problem Description Great! Your new software is almost finished! The only thing left to

hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费. 思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 4901 The Romantic Hero(DP)

HDU 4901 The Romantic Hero 题目链接 题意:给定一个序列,要求找一个分界点,然后左边选一些数异或和,和右边选一些数且和相等,问有几种方法 思路:dp,从左往右和从右往左dp,求出异或和且的个数,然后找一个分界点,使得一边必须在分界点上,一边随意,然后根据乘法原理和加法原理计算 代码: #include <cstdio> #include <cstring> typedef __int64 ll; const int N = 1024; const int