Jzoj3177 安全监控

227 篇文章 3 订阅
153 篇文章 0 订阅

选举越来越近了,所以总统Amabo Kcarab准备在美国计划一次旅行,并在WDC和LA进行演讲。特务为了能够保护总统的安全,需要时刻监控所有总统会经过的城市(包括WDC和LA)。

当然,为了使预算不会太大,总统不会用到AF1,而会用汽车作为交通工具。并且,特务计划在总统从WDC到LA和回到WDC的旅途中安排尽可能少的需要监控的城市数目。

对于这个问题,我们假设美国有N(N<=100)个城市,标号为1到N,和M(M<=200)条单向的连接两个不同城市的州际公路。WDC的编号为1,LA的编号为2。

写一个程序计算出最少需要被监控的城市,使得有一条路只经过被监控的城市,可以从WDC到LA,最后回到WDC。


智商下降招来杀身之祸暂来机房躲避顺便更新一下

好的这道题目非常经典但是不是很好做

第一个做法是直接dfs,因为可以通过floyd求出上界来进行最优性剪枝,对于这个范围可以快速通过

但是这样不保险,我们还是考虑一下正经的做法

首先跑出dis[i][j]表示i到j的最短路长度,直接floyd

考虑用dp,设f[i][j]表示从j出发去到1,再从1到i所需的最少被监控的城市数量,显然f[1][1]=1,f[2][2]就是答案

运用类似dijkstra的做法,我们可以得到f的转移方程(用优先队列进行转移)

f[j][i]+dis[j][i]-1=>f[i][j]  (i≠j)

f[i][j]+1=>f[v][j]  ( i->v∈G且v≠j )

f[i][j]+1=>f[i][v]  ( j->v∈~G且v≠i )

f[i][j]=>f[i][i] ( j->i∈~G )

f[i][j]=>f[j][j] ( i->j∈G )

其中G是原图,~G是反图

后面四个应该比较好理解,至于第一个式子,可以理解为:

f[j][i]表示i->1->j,那么再加上dis[i][j]就可以成为j->i->1->j->i,这个路径上除了j->i这一段是新增的其他应该和i->1->j相等,而j->i的点数即为dis[j][i]

让后直接跑dijkstra即可

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110
using namespace std;
struct node{ int d,x,y; } t;
struct edge{ int v,nt; } G[N<<2];
int f[N][N],g[N][N],h[N],h2[N],n,m,cnt=0;
inline bool gmin(int& x,int y){ return x>y?x=y:0; }
inline bool operator< (node a,node b){ return a.d>b.d; }
inline void adj(int x,int y){
	G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
	G[++cnt]=(edge){x,h2[y]}; h2[y]=cnt;
}
int main(){
	scanf("%d%d",&n,&m);
	memset(f,0x3f,sizeof f);
	memset(g,0x3f,sizeof g);
	for(int x,y;m--;){
		scanf("%d%d",&x,&y);
		f[x][y]=1; adj(x,y); 
	}
	for(int k=1;k<=n;++k)
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
	priority_queue<node> q;
	g[1][1]=1; q.push((node){1,1,1});
	for(int x,y;!q.empty();){
		t=q.top(); q.pop();
		if(g[x=t.x][y=t.y]<t.d) continue;
		gmin(g[x][y],g[y][x]+f[y][x]-(x!=y));
		for(int v,i=h[x];i;i=G[i].nt)
			if(gmin(g[v=G[i].v][y],g[x][y]+(G[i].v!=y))) q.push((node){g[v][y],v,y});
		for(int v,i=h2[y];i;i=G[i].nt)
			if(gmin(g[x][v=G[i].v],g[x][y]+(G[i].v!=x))) q.push((node){g[x][v],x,v});
	}
	printf("%d",g[2][2]);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值