ChiBi ZOJ - 3080

题意:曹操有一些船,这些船很多是连在一起的,现在让你派一些士兵去烧船,其中要求派出的士兵数最少(隐含意:由于一些船是连在一起的,所以就是一个连通块派出一个士兵)现在问你烧掉所有的船所需要的最少时间。

思路:先使用并查集将每个联通快,直接标记即可,然后遍历每个联通快里的节点,找出每个烧掉每个联通快所需要的最少时间,然后取所有联通快烧掉时所用时间最长的一个。

#include <bits/stdc++.h>

using namespace  std;
const int maxn=1050;
int n;
int mat[maxn][maxn];
vector<int> v[maxn];
int a[maxn];
vector<int> sub[maxn];
int vis[maxn];
int id[maxn];
int t[maxn];
int inq[maxn];
const int inf=0x3f3f3f;
int dis[maxn];
int fa[maxn];
void Init()
{
    for(int i=0; i<=n; i++)
    {
        v[i].clear();
        fa[i]=i;
    }

}
int Find_x(int x)
{
    return fa[x]=(x==fa[x]?x:Find_x(fa[x]));
}
int spfa(int u)
{
    queue<int> p;
    p.push(u);
    memset(inq,0,sizeof(inq));
    inq[u]=1;

    memset(dis,inf,sizeof(dis));
    dis[u]=0;
    while(!p.empty())
    {
        int s=p.front();
        p.pop();
        inq[s]=0;
        for(int i=0; i<v[s].size(); i++)
        {
            int son=v[s][i];
            if(dis[son]>dis[s]+mat[s][son])
            {
                dis[son]=dis[s]+mat[s][son];
                if(!inq[son])
                {
                    inq[son]=1;
                    p.push(son);
                }
            }
        }
    }
    int ans=0;
    for(int i=1; i<=n; i++)
    {
        if(dis[i]<inf)///很奇怪的地方,dis[i]无缘无故变得比inf还大
        {
            ans=max(dis[i],ans);
        }
    }
    return ans;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(t,inf,sizeof(t));
        Init();
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&mat[i][j]);
                if(mat[i][j]!=-1)
                {
                    v[i].push_back(j);
                    int fx=Find_x(i);
                    int fy=Find_x(j);
                    fa[fx]=fy;///因为图是对称的,这样合并以后,每个联通快的里的fa都相同。
                }
            }
        }
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        for(int i=1; i<=n; i++)
        {
            t[fa[i]]=min(spfa(i)+a[i],t[fa[i]]);
        }
        int ans=0;
        for(int i=1; i<=n; i++)
            ans=max(ans,t[fa[i]]);
        cout<<ans<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值