zoukankan      html  css  js  c++  java
  • P4610 [COCI2011-2012#7] KAMPANJA

    题目背景

    临近选举,总统要在城市1和城市2举行演讲。他乘汽车完成巡回演讲,从1出发,途中要经过城市2,最后必须回到城市1.特勤局对总统要经过的所有城市监控。为了使得费用最小,必须使得监控的城市最少。求最少要监控的城市。

    题目描述

    一共有N个城市,有M条有向边。(0<=N,M<=200)有N从1出发途中要经过2,最后要回到1的路线中最少要经过的点的数目。

    输入输出格式

    输入格式:

    第一行包含2个整数N,MN表示城市的数目,M表示有向边的数目。 接下来M行,每行两个数A,B,表示从AB有一条有向边。

    输出格式:

    最少要监控的城市的数量。

    输入输出样例

    输入样例#1: 
    6 7
    1 3
    3 4
    4 5
    5 1
    4 2
    2 6
    6 3
    输出样例#1: 
    6

    说明

    0<=N,M<=200

    本题数据加强by Imagine

    Solution:

      本题最短路+dp。

      我们先用floyd预处理出$w[i][j]$,表示$i ightarrow j$经过的最少点数(除了i)。

      由于要求$1 ightarrow 2 ightarrow 1$经过的最少点数,而模型是个有向图,考虑dp,定义状态$f[i][j]$表示$1 ightarrow i ightarrow j ightarrow 1$经过的最少点数,初始化$f[1][1]=1$,状态转移方程:$f[x][y]=min(f[x][y],f[a][b]+w[b][x]+w[x][y]+w[y][a]-1)$(注意-1是因为a被多算了1次),直接dp显然是有后效性的,注意到每次由小的点对更新状态肯定最优,于是状态转移时套用堆优化dijkstra,用全局最小值$f[a][b]$去更新状态就好了。

      转移时还需注意不能用点对$f[a][b]$更新自己(当a==b时直接RE)。

      时间复杂度$O(n^3log n)$

    代码:

    /*Code by 520 -- 9.4*/
    #include<bits/stdc++.h>
    #include<ext/pb_ds/assoc_container.hpp>
    #include<ext/pb_ds/priority_queue.hpp>
    #define il inline
    #define ll long long
    #define RE register
    #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    using namespace __gnu_pbds;
    const int N=205,inf=233333333;
    int n,m,w[N][N],dis[N][N];
    struct node{
        int u,v,d;
        bool operator<(const node &a)const{
            if(d==a.d&&u==a.u)return v>a.v;
            if(d==a.d)return u>a.u;
            return d>a.d;
        }
    };
    typedef __gnu_pbds::priority_queue<node,less<node>,pairing_heap_tag> heap;
    heap q;
    heap::point_iterator id[N][N];
    
    int main(){
        scanf("%d%d",&n,&m);
        For(i,1,n) For(j,1,n) w[i][j]=i==j?0:inf,dis[i][j]=inf;
        int u,v;
        while(m--) scanf("%d%d",&u,&v),w[u][v]=1;
        For(k,1,n) For(i,1,n) For(j,1,n) w[i][j]=min(w[i][j],w[i][k]+w[k][j]);
        dis[1][1]=1,id[1][1]=q.push(node{1,1,dis[1][1]});
        while(1){
            node x=q.top();
            int a=x.u,b=x.v;q.pop();
            if(a==2&&b==2)break;
            For(c,1,n) For(d,1,n) {
                if(a==c&&b==d)continue;
                if(dis[a][b]+w[b][c]+w[c][d]+w[d][a]-1<dis[c][d]){
                    dis[c][d]=dis[a][b]+w[b][c]+w[c][d]+w[d][a]-1;
                    if(id[c][d]==0)id[c][d]=q.push(node{c,d,dis[c][d]});
                    else q.modify(id[c][d],node{c,d,dis[c][d]});
                }
            }
        }
        cout<<dis[2][2];    
        return 0;
    }

     

  • 相关阅读:
    学习笔记—二进制和精度问题
    学习笔记—Buffer的常用方法与实现
    学习笔记—Node中第三方模块
    学习笔记—npm的介绍与使用
    .NET中序列化(一)
    .NET中序列化(二)
    JavaScript在多浏览器下杂谈1for循环
    .NET中序列化(三)
    DLCB额度切分
    DLCB解决问题的思路
  • 原文地址:https://www.cnblogs.com/five20/p/9589063.html
Copyright © 2011-2022 走看看