搜索+剪枝——运筹帷幄 (road.cpp)

运筹帷幄

(road.cpp)

【题目描述】

刘邦军行至迷糊林,见其中瘴气围绕,又有青狼猛虎之兽,难于前行。

已知迷糊林是一个共有n个结点的图,点与点之间共有m条道路相连接,每条路有参数t,c,分别表示行走于该路的时间以及兵士损失量。你已知道,刘邦除了脸皮厚什么都不会而且兵力少得可怜,所以需要在还能有兵士存活的情况下尽快走出迷糊林。

刘邦踞鞍而问曰:“子房,如之奈何?”。

【文件格式】
输入文件:

第一行两个整数n,m,表示节点数以及边数。

以下m行每行4个整数u,v,c,t,表示u点以及v点之间有一条参数为c,t的边,c为兵士损失量,t为耗费时间。

第m+2行有两个整数s,t,表示起点与终点。

第m+3行有一个整数k,表示刘邦军的兵力。

输出文件:

一个整数表示能走出迷糊林的最短时间,如果不能走出请输出-1。

【样例数据】

Input(road.in)
4 5
1 2 2 3
1 3 3 5
1 4 7 10
2 4 4 6
3 4 2 6
1 4
5

Output (road.out)

11

【数据约定】

n<=5000 ,m<=40000 , c,d<=300 , k<=10^9

[Hint]

本题数据随机生成。

【题目思路】

这个题主要是搜索,bfs,不过要是只用单纯的搜索的话绝对会超时,超的不止一点。。。。。所以我用了两种剪枝,第一是先spfa一遍图,算出每个点到终点的最短距离,如果当前搜到的点+这个点到终点的最短距离(士兵数)<拥有的士兵总量,直接过;第二是如果时间超过了当前存储的最小时间(迷糊林路的长度),直接过。

下面上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>

using namespace std;

const int N = 40000+10;

struct Edge { int v,b,t,next;
}e[N*2];
int en=0,front[N];

int m,n,u,v,b,t;
int qi,zhong;
int liu;
int d[40001];

void adde(int u,int v,int b,int t) {
	en++; e[en].v=v , e[en].b=b , e[en].t=t , e[en].next=front[u];
	front[u]=en;
}

void spfa() {
	queue<int> q;
	bool inq[40001];
	memset(inq,0,sizeof(inq));
	for(int i=1;i<=m;i++) d[i]=1e9+1e9;
	d[zhong]=0;inq[zhong]=1; q.push(zhong);
	while(!q.empty())
	{
		int u=q.front(); q.pop(); inq[u]=false;
		for(int i=front[u];i;i=e[i].next) {
			Edge es=e[i];
			int v=es.v;
			if(d[v]>d[u]+es.b) {
				d[v]=d[u]+es.b;
				if(!inq[v])
					q.push(v) , inq[v]=1;
			}
		}
	}
}

bool dg[5001];
int bd=0,bt=0;
int small=1e9;

void dfs(int u,int blood,int dist)
{
	if(u==zhong) { small=dist; return; }
 	for(int i=front[u];i;i=e[i].next) {
		Edge es=e[i];
		if(!dg[es.v] && blood-es.b > d[es.v] && dist + es.t < small) {
			dg[es.v]=1;
			dfs(es.v,blood-es.b,dist+es.t);
			dg[es.v]=0;
		}
	}
}
void read(int& x) {
	char c=getchar();
	while(!isdigit(c)) c=getchar();
	x=0;
	while(isdigit(c)) {
		x=x*10+c-‘0‘;
		c=getchar();
	}
}
int main()
{
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	read(m),read(n);
	 //memset(dg,0,sizeof(dg));
	 for(int i=1;i<=n;i++)
	 {
	 	read(u),read(v),read(b),read(t);
	 	adde(u,v,b,t); adde(v,u,b,t);
	 }
	 read(qi),read(zhong),read(liu);
	 spfa();
	 if(d[qi] > liu)
	 {
	 	cout<<"-1";
	 }
	 else
	 {
	 	dg[qi]=1;
	 	dfs(qi,liu,0);
	 	cout<<small;
	 }
	 return 0;
}

  数据:http://files.cnblogs.com/files/zhangone/road.zip

(以上代码数据中十个点全过)

感谢李学长在我各种蒟蒻的时候耐心讲解。

时间: 2024-10-25 01:53:54

搜索+剪枝——运筹帷幄 (road.cpp)的相关文章

【搜索剪枝】HDU 5469 Antonidas

通道 题意:给出1字母树,询问一字符串是否出现在该树中 思路:直接搜索剪枝,有人点分治?写了几发都T了..有人会了教我? 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Edge { int v, nxt; Edge () { } Edge (int _v, int _n) { v = _v, nxt = _n; } }; const in

poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)

题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一个边界外,跳到了另一边的边界外,每跳一次对那个点进行标记. 现在给你很多青蛙跳过后的所标记的所有点,那请你从这些点里面找出 一条可能的路径里面出现过的标记点最多. 分析:先排序(目的是方便剪枝,break),然后枚举两个点,这两个 点代表这条路径的起始的两个点.然后是三个剪枝,下面有. 开始遍历时,

USACO/fence8 迭代加深搜索+剪枝

题目链接 迭代加深搜索思想. 枚举答案K,考虑到能否切出K个木头,那么我们当然选最小的K个来切. 1.对于原材料,我们是首选最大的还是最小的?显然,首选大的能够更容易切出,也更容易得到答案. 2.对于目标木头,我们是优先得到最大的还是最小的?显然,由于K个木头我们都要得到,那么当然先把最大的(最难得到的)先得到,这种搜索策略更优. 3.假设总原材料为all,前K个木头总和为sum,那么all-sum就是这一次切割过程中能[浪费]的最大数目.对于一个切剩下的原材料,若它比最小的目标木头还要小,则它

hdu 5887 搜索+剪枝

Herbs Gathering Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 687    Accepted Submission(s): 145 Problem Description Collecting one's own plants for use as herbal medicines is perhaps one of t

poj 2531 搜索剪枝

Network Saboteur Time Limit: 2000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description A university network is composed of N computers. System administrators gathered informat

【迭代博弈+搜索+剪枝】poj-1568--Find the Winning Move

poj  1568:Find the Winning Move   [迭代博弈+搜索+剪枝] 题面省略... Input The input contains one or more test cases, followed by a line beginning with a dollar sign that signals the end of the file. Each test case begins with a line containing a question mark and

『生日蛋糕 搜索剪枝』

Description 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为N×π的M层生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱.当i < M时,要求Ri > Ri+1且Hi > Hi+1. 由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小. 令Q = S×π请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小.(除Q外,以上所

搜索 + 剪枝 --- POJ 1101 : Sticks

Sticks Problem's Link:   http://poj.org/problem?id=1011 Mean: http://poj.org/problem?id=1011&lang=zh-CN&change=true analyse: 爆搜,但是其中蕴含着很多剪枝. Time complexity: O(n^2) Source code:  // Memory Time // 1347K 0MS // by : Snarl_jsb // 2014-11-07-17.14 #i

poj 1198 hdu 1401 搜索+剪枝 Solitaire

写到一半才发现可以用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个很水的剪枝,h函数为  当前点到终点4个点的最短距离加起来除以2,因为最多一步走2格,然后在HDU上T了,又发现再搜索过程中,这个估价函数应该是递减的(贪心),再加上这个剪枝就过了. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<list> #