• [WC2008]游览计划


    【题目描述】

    从未来过绍兴的小 D 有幸参加了Winter Camp 2008,他被这座历史名城的秀丽风景所吸引,强烈要求游览绍兴及其周边的所有景点。

    主办者将绍兴划分为 N 行M 列(N×M)个方块,如下图(8×8)

    景点含于方块内,且一个方块至多有一个景点。无景点的方块视为路。

    为了保证安全与便利,主办方依据路况和治安状况,在非景点的一些方块内安排不同数量的志愿者;在景点内聘请导游(导游不是志愿者)。在选择旅游方案时,保证任意两个景点之间,存在一条路径,在这条路径所经过的每一个方块都有志愿者或者该方块为景点。既能满足选手们游览的需要,又能够让志愿者的总数最少。

    例如,在上面的例子中,在每个没有景点的方块中填入一个数字,表示控制

    该方块最少需要的志愿者数目:

    图中用深色标出的方块区域就是一种可行的志愿者安排方案,一共需要20名志愿者。由图可见,两个相邻的景点是直接(有景点内的路)连通的(如沈园和八字桥)。

    现在,希望你能够帮助主办方找到一种最好的安排方案。

    【输入格式】

    输入文件中 trip.in 中第一行有两个整数,N 和M,描述方块的数目。

    接下来 N 行,每行有M 个非负整数,如果该整数为0,则该方块为一个景点;否则表示控制该方块至少需要的志愿者数目。相邻的整数用(若干个)空格隔开,行首行末也可能有多余的空格。

    【输出格式】

    输出一行一个整数,即最少的志愿者总数。

    【样例输入】

    4 4
    0 1 1 0
    2 5 5 1
    1 5 5 1
    0 1 1 0

    【样例输出】

    6

    【提示】

    样例方案:

    其中红色方块安排了志愿者。

    所有的 10 组数据中N, M ,以及景点数 K 的范围规定如下:

    输入文件中的所有整数均不小于 0 且不超过2^16。

    题解:

    裸斯坦纳树,直接spfa+子集dp,暴力更新就行.

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <queue>
     8 using namespace std;
     9 typedef pair<int,int>par;
    10 const int N=12;
    11 int n,m,INF,map[N][N],f[N][N][1<<10],S=0,mx[4]={0,0,1,-1},my[4]={1,-1,0,0};
    12 bool vis[N][N];
    13 queue<par>q;
    14 void spfa(int k){
    15     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
    16         if(f[i][j][k]!=INF)
    17              q.push(par(i,j));
    18     int x,y,tx,ty;
    19     while(!q.empty()){
    20         x=q.front().first;y=q.front().second;q.pop();
    21         for(int i=0;i<4;i++){
    22             tx=x+mx[i];ty=y+my[i];
    23             if(tx<1 || tx>n || ty<1 || ty>m)continue;
    24             if(f[x][y][k]+map[tx][ty]<f[tx][ty][k]){
    25                 f[tx][ty][k]=f[x][y][k]+map[tx][ty];
    26                 if(!vis[tx][ty])q.push(par(tx,ty)),vis[tx][ty]=true;
    27             }
    28         }
    29         vis[x][y]=false;
    30     }
    31 }
    32 void work(){
    33     scanf("%d%d",&n,&m);
    34     memset(f,127/3,sizeof(f));
    35     for(int i=1;i<=n;i++)
    36         for(int j=1;j<=m;j++){
    37             scanf("%d",&map[i][j]);
    38             if(!map[i][j])f[i][j][1<<(S++)]=0;
    39         }
    40     int states=(1<<S)-1;INF=f[0][0][0];
    41     for(int s=1;s<=states;s++){
    42         for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
    43             for(int k=(k-1)&s;k;k=(k-1)&s){
    44                 if(f[i][j][k]+f[i][j][s-k]-map[i][j]<f[i][j][s])
    45                     f[i][j][s]=f[i][j][k]+f[i][j][s-k]-map[i][j];
    46             }
    47          spfa(s);
    48     }
    49     int ans=INF;
    50     for(int i=1;i<=n;i++)
    51         for(int j=1;j<=m;j++)
    52             if(f[i][j][states]<ans)
    53                 ans=f[i][j][states];
    54     printf("%d
    ",ans);
    55 }
    56 int main()
    57 {
    58     freopen("wc2008_trip.in","r",stdin);
    59     freopen("wc2008_trip.out","w",stdout);
    60     work();
    61     return 0;
    62 }
  • 相关阅读:
    简述at和crontab命令
    自建yum仓库,分别为网络源和本地源
    简述rpm与yum命令的常见选项
    用户目录权限管理.手动添加用户.截取用户信息
    总结描述用户和组管理类命令的使用方法,系统用户相关信息,取出主机IP地址
    Android独立交叉编译环境搭建
    Python编程总结之常用三方模块
    GDB常用命令简介
    linux内核中task_struct与thread_info及stack三者的关系
    在Linux-PC上建立kdump调试环境
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7196883.html
Copyright © 2020-2023  润新知