光玉小镇

光玉小镇

https://ac.nowcoder.com/acm/contest/6874/C

看到且‘T’的数目大于等于1并且小于等于15,考虑状压dp可以记录当前修理的状态和最后所在的电线杆,设f[i][j]表示当前集合为i且最后所在的电线杆为j的代价,先预处理家与电线杆之间的距离和两两电线杆之间的距离,并转移即可

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define int long long
using namespace std;
const int INF=0x3f3f3f3f;
int read()
{
    int s=0,bj=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')bj|=(ch=='-'),ch=getchar();
    while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
    return bj?-s:s;
}
void printnum(int x)
{
    if(x>9)printnum(x/10);
    putchar(x%10^48);
}
void print(int x,char ch)
{
    if(x<0){putchar('-');x=-x;}
    printnum(x);putchar(ch);
}
int n,m,t;
char ch[205][205];
bool vst[205][205];
struct node
{
    int x,y;
    bool operator < (const node &a) const {return x==a.x?y<a.y:x<a.x;}
}s,num[16];int cnt;
int f[1<<15][16],dis[16],d[16][16];
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int ans=0x3f3f3f3f;
int Get(node S,node T)
{
    node tmp,ret;int nx,ny;
    memset(vst,0,sizeof(vst));
    priority_queue<pair<int,node> >q;
    vst[S.x][S.y]=1;q.push(make_pair(0,S));
    while(!q.empty())
    {
        int no=-q.top().first;tmp=q.top().second;q.pop();
        for(int i=0;i<4;++i)
        {
            nx=tmp.x+dx[i];ny=tmp.y+dy[i];
            if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!vst[nx][ny]&&(ch[nx][ny]^'#'))
            {
                if(nx==T.x&&ny==T.y)return no+1;
                vst[nx][ny]=1;ret.x=nx;ret.y=ny;q.push(make_pair(-no-1,ret));
            }
        }
    }
    return INF;
}//搜索计算距离 
signed main()
{
    n=read();m=read();t=read();
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;++i)
    {
        scanf("%s",ch[i]+1);
        for(int j=1;j<=m;++j)
        {
            if(ch[i][j]=='S'){s.x=i;s.y=j;}
            else if(ch[i][j]=='T'){num[cnt].x=i;num[cnt].y=j;++cnt;}
        }
    }//记录家,电线杆的坐标 
    for(int i=0;i<cnt;++i)
    {
        f[1<<i][i]=dis[i]=Get(s,num[i]);
        if(dis[i]==INF){print(-1,'\n');return 0;}
        for(int j=i+1;j<cnt;++j)d[i][j]=d[j][i]=Get(num[i],num[j]);
    }//预处理距离 
    for(int i=0;i<(1<<cnt);++i)
    for(int j=0;j<cnt;++j)
    if((1<<j)&i)//在i集合中存在j 
    {
        for(int k=0;k<cnt;++k)
        if(!((1<<k)&i))//在i集合内没有k,才能转移 
        f[(1<<k)|i][k]=min(f[(1<<k)|i][k],f[i][j]+d[j][k]);//由j走到k 
    }
    for(int i=0;i<cnt;++i)ans=min(ans,f[(1<<cnt)-1][i]+dis[i]);//对于每一个结束的电线杆取min 
    print(ans+cnt*t,'\n');//最后一起加上修理的时间 
    return 0;
}
全部评论

相关推荐

hso_:哈哈哈哈哈哈我没offer一样在同一道题开喷了
投递深圳同为数码等公司10个岗位
点赞 评论 收藏
分享
努力成为C语言高手:质疑大祥老师,理解大祥老师,成为大祥老师
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务