HDU 3873 Invade the Mars 2011 Multi-University Training Contest 4 - Host by SDU

/*
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3873
最短路的巧妙运用,本题较最短路问题多出了保护城市的条件,即一个城市x受若干城市保护,没有攻占所有保护x的“卫星城”就不可以攻占x
dij过程中要维护其保护城市,用les[x]记录x所有“卫星城”被攻占的最早时间,那么能到x的最短时间为les[x]和到达x的最短路中的较大者
处理特点:
dij入队过程中只把in[x](没有被包含的城市)入队
对于出对的x,它的最短时间已经确定,表示已经被占领,它所保护的城市的保护度减 1,一旦某个被保护的城市的保护度为零且已经到底(未占领,d[x]!=inf),就可以确定到达它的
最短时间(为max(les[x],d[x])),它也就到了入队的时机。
*/
#include <cstdio>
#include <iostream>
#include <memory.h>
#include<queue>
using namespace std;
const int MAXM=70009;
const int MAXN=3009;
const long long inf=(1LL)<<54;
int n,m;
struct Edge
{
    int v,w,next;
}edge[MAXM];
int first[MAXN],e,in[MAXN],vis[MAXN];//in[i]   i的保护度(被几个城市保护)
long long les[MAXN];		//les[i]表示所有保护i的点被摧毁的最早时间
long long d[MAXN];         //d[i]表示到底i的最短时间
vector<int> node[MAXN];    //node[i]中存放被i保护的节点

void add(int u,int v,int w)
{
    edge[e].v=v;edge[e].w=w;edge[e].next=first[u];
    first[u]=e++;
}

void init()
{
    scanf("%d%d",&n,&m);
    int u,v,w,k;
    e=0;
    for(int i=1;i<=n;i++)
    {
        node[i].clear();
        in[i]=0;
		vis[i]=0;
		d[i]=inf;
        first[i]=-1;
        les[i]=0;
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
	
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&in[i]);    //点i的受保护数
        for(int j=0;j<in[i];j++)
        {
            scanf("%d",&k);
            node[k].push_back(i);//i点压入k的保护之中
        }
    }
}


typedef pair<long long,int> pii;
long long dij(int s)
{
    
    d[s]=0;
    priority_queue<pii,vector<pii>,greater<pii> > q;
    q.push(make_pair(d[s],s));
    while(!q.empty())
    {
        pii u=q.top();q.pop();
		
        int x=u.second;
        if(vis[x])continue;
        vis[x]=1;
		
		int size=node[x].size();
		for(int j=0;j<size;j++)           //x已被摧毁,维护它包含的节点的信息
		{
			int tmp=node[x][j];
			in[tmp]--;                    //所有x包含的节点的入度减一
			les[tmp]=max(les[tmp],d[x]); //更新所保护节点的最早脱离保护的时间
			if(d[tmp]!=inf&&in[tmp]==0) //如果所包含点已经到达且脱离保护,到底其的最短时间为max(脱离保护时间,到达时间),并将其入队
			{
				d[tmp]=max(d[tmp],les[tmp]);
				q.push(make_pair(d[tmp],tmp));
			}
		}
		
        for(int k=first[x];k!=-1;k=edge[k].next)
        {
            int v=edge[k].v;
            if(d[v]>d[x]+edge[k].w)
            {
                d[v]=max(d[x]+edge[k].w,les[v]);
				if(in[v]==0)                 //只有这个点为无保护点才可以入队
				{
				//d[v]=max(d[v],les[v]);
                q.push(make_pair(d[v],v));
				}
            }
        }
    }
    return d[n];
}

void solve()
{
	dij(1);
    printf("%I64d\n",d[n]);
}
int main () 
{
    int Case;
    scanf("%d",&Case);
    while(Case--)
    {
        init();
        solve();
    }
    return 0;    
}
/*
1
6 6
1 2 1
1 4 3
2 3 5
2 5 2
4 6 2
5 3 2
0
0
0
1 3
0
2 3 5
*/


你可能感兴趣的:(Training,pair)