*点击

[洛谷P4772]灰化肥,会挥发

题目

Description

在 Farmer Justin 的农场中有许多灰化肥,它们都堆积在A仓库里。为了方便施肥,Farmer Justin 需要修一些公路使得他能用拖拉机把这些灰化肥拉到其他仓库里。由于 Farmer Justin 及其懒惰,所以他只想一次拉完所有的灰化肥送到其他仓库里。但是灰化肥见光易挥发,所以 Farmer Justin 需要尽快把这些灰化肥拉完。现在告诉你Farmer Justin农场的构成地图,请你帮帮他计划一条从 A 仓库出发走完所有仓库的方案吧!由于Farmer Justin 非常的讨厌浪费时间,所以你只需要告诉他最短的距离和走过所有农场的顺序。(注意:拖拉机走的时候是四联通的。)

 

Input

第一行三个正整数 R,C,N分别表示地图大小和仓库数量。 下面给出一个 R 行 C 列的地图,其中 . 表示空地,可以修建公路;* 表示是 Farmer Justin 的农业区,不可以修建公路;用大写字母表示仓库编号。

Output

第一行一个正整数表示最短的距离。

第二行表示拖拉机走过仓库的方案(由仓库编号组成的字符串)。若有多种方案,输出字典序最小的方案。

数据保证有解。

Sample Input

5 5 3
A.**C
*....
B*...
.**..
.....

Sample Output

16
ACB

思路

因为要经过所有仓库,所以自然而然地想到用状压$dp$来处理最短距离和经过的仓库;

只需先用$BFS$预处理每个仓库之间的最短距离即可;

状态转移方程就为;

$dp[i][k]=min(dp[i][k],dp[j][k \oplus (1<<(i-1))]+a[j][i]);$

$s[i][k]=s[j][k \oplus (1<<(i-1))]+char(i+'A'-1);$

$k$表示经过的仓库集合,$i$表示当前经过的仓库;

题目要求经过字典序最小,用$if$判断一下即可;

 


 

代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll _=501;
ll n,m,t;
char c[_][_];
ll d[_][_],f[_][_];
ll dx[5]={0,0,1,0,-1};
ll dy[5]={0,1,0,-1,0};
ll a[17][17],dp[17][1<<16];
string s[17][1<<16];
struct node
{
    ll x,y;
};
queue<node> q;
bool check(ll x,ll y)
{
    if(x>0&&x<=n&&y>0&&y<=m)
        return 1;
    return 0;
}
void bfs(ll x,ll y,char s)
{
    memset(f,0,sizeof(f));
    memset(d,0,sizeof(d));
    node num,nxt;
    num.x=x; num.y=y;
    f[x][y]=1;
    q.push(num);
    while(!q.empty())
    {
        num=q.front(); q.pop();
        for(ll i=1;i<=4;i++)
        {
            nxt.x=num.x+dx[i];
            nxt.y=num.y+dy[i];
            if(check(nxt.x,nxt.y)&&!f[nxt.x][nxt.y]&&c[nxt.x][nxt.y]!='*')
            {
                d[nxt.x][nxt.y]=d[num.x][num.y]+1;
                f[nxt.x][nxt.y]=1;
                if(c[nxt.x][nxt.y]>='A'&&c[nxt.x][nxt.y]<='Z')
                {//如果nxt点是仓库,则记录两仓库的距离
                    a[s-'A'+1][c[nxt.x][nxt.y]-'A'+1]=d[nxt.x][nxt.y];
                    a[c[nxt.x][nxt.y]-'A'+1][s-'A'+1]=d[nxt.x][nxt.y];
                }
                q.push(nxt);
            }
        }
    }
}
int main()
{
    memset(dp,127,sizeof(dp));
    scanf("%lld%lld%lld",&n,&m,&t);
    for(ll i=1;i<=n;i++)
    for(ll j=1;j<=m;j++)
        cin>>c[i][j];
    for(ll i=1;i<=n;i++)
    for(ll j=1;j<=m;j++)
    if(c[i][j]>='A'&&c[i][j]<='Z')
        bfs(i,j,c[i][j]);//以每个仓库为起点,计算其他仓库到这个仓库的距离
    dp[1][1]=0;//从第一个仓库出发
    for(ll k=1;k<=(1<<t)-1;k+=2)
    for(ll i=1;i<=t;i++)
    for(ll j=1;j<=t;j++)
    if(k&(1<<(i-1))&&k&(1<<(j-1)))
    {
        if(dp[i][k]==dp[j][k^(1<<(i-1))]+a[j][i])//如果距离相等,则记录字典序最小的路径
            s[i][k]=min(s[i][k],s[j][k^(1<<(i-1))]+char(i+'A'-1));
        if(dp[i][k]>dp[j][k^(1<<(i-1))]+a[j][i])
        {
            dp[i][k]=dp[j][k^(1<<(i-1))]+a[j][i];//状态转移
            s[i][k]=s[j][k^(1<<(i-1))]+char(i+'A'-1);
        }
    }
    ll ans=INT_MAX;
    string ss;
    for(ll i=2;i<=t;i++)
    {
        if(ans==dp[i][(1<<t)-1])//距离相等,找字典序最小的路径
            ss=min(ss,s[i][(1<<t)-1]);
        if(ans>dp[i][(1<<t)-1])
        {
            ans=dp[i][(1<<t)-1];
            ss=s[i][(1<<t)-1];
        }
    }
    printf("%lld\n",ans);
    cout<<"A"<<ss;
    return 0;
}

 

 

 

 

 

 

 

posted @ 2024-12-18 20:53  木偶人-怪咖  阅读(5)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录