• Jzoj3177 安全监控


    选举越来越近了,所以总统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]);
    }

  • 相关阅读:
    数据结构中的知识
    Java中的小知识
    安装Linux虚拟机
    2.Two Sum
    1005. Maximize Sum Of Array After K Negations
    Leetcode刷题记录
    Markdown的使用笔记
    CCF历年试题总结
    在Linux上搭建Hadoop
    配置和使用连接池
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477156.html
Copyright © 2020-2023  润新知