您的位置:首页 > 其它

HDU 3873 必须写一个解题报告,很神奇的最短路

2011-07-25 19:16 323 查看
此题就是要求一个最短路,但是有一个约束条件:到达该点的时间以前必然可以到达某些保护他的节点(protect(i)表示)。借来70学长的代码观摩了一下。发现时用队列和优先队列迭代求最短路以及达到题目要求的。

首先设计标记chk[i] = 0 , 1, 2 0表示没占领且没达到,1表示达到了但是没有占领,2表示占领了改该节点。

对于每个点记录一下几个值

1. dist[i] 已经被从1开始一次占领若干节点最后占领i节点的最短距离。dist[i] = min(dist[pre] + value[pre][i]);

2. maxn[i] 表示占领所有保护他的节点的的时间的最大值。 maxn[i] = max(ans[u] u属于proctect(i))

3. ans[i] 表示占领i节点的最短时间。

可以得到ans[i] = max(dist[i], maxn[i]);

然后用队列和优先队列进行处理

每次只有chk[i] == 2的点如对,并对i保护的点除去保护deg[i]--;然后所以未求出最短路且未占领的点松弛送入优先队列。只是队列空为止。然后在优先队列里。松弛节点记录dist[i] 。如果优先队列里的节点还有deg(还被保护着),则标记chk[i] = 1;否则ans[i] = max(dist[i], maxn[i])(这里其实取的就是dist[i],因为maxn[i]一定比dist[i]大,他还在堆里要不就还没进堆呢……)。最后chk[i] == 1的如何处理呢?如果chk[i] == 1且除去保护点的过程中发现deg[i] == 0了,就可以ans[i] = max(dist[i], maxn[i])(其实这里取的就是maxn[i],原因你懂的)

代码如下:

hdu 3873

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define FOREACH(i, con) for(__typeof(con.begin()) i = con.begin();i != con.end();++i)
#define CC(con, i) memset(con, i, sizeof(con))
using namespace std;
typedef long long LL;
const int N = 3000;
const LL INF = 1ll << 40;
LL dist
, maxn
, ans
;
int deg
, chk
;
vector<pair<int, LL> > g
;
vector<int> lmt
;
struct status
{
long long d;
int v;
bool operator < (const status& a) const
{
return d > a.d;
}
status(int v = 0, long long d = 0)
{
this->d = d;
this->v = v;
}
};
int main()
{
int t, n, m;
scanf("%d", &t);
while(t-- && scanf("%d %d", &n, &m) == 2)
{
int a, b;
LL val;
for(int i = 0; i < n; i++) g[i].clear();
for(int i = 0; i < n; i++) lmt[i].clear();
CC(deg, 0);
for(int i = 0; i < m; i++)
{
scanf("%d %d %I64d", &a, &b, &val);
a--, b--;
g[a].push_back(make_pair(b, val));
}
for(int i = 0; i < n; i++)
{
scanf("%d", °[i]);
for(int j = 0; j < deg[i]; j++)
{
scanf("%d", &a);
a--;
lmt[a].push_back(i);
}
}
queue<int> q;
priority_queue<status> pq;
CC(maxn, 0);CC(chk, 0);
fill(ans, ans + n, INF);
fill(dist, dist + n, INF);
q.push(0);
chk[0] = 2;
maxn[0] = ans[0] = dist[0] = 0;
//chk[i] == 2进队
while(!q.empty() || !pq.empty())
{
while(!q.empty())
{
int v = q.front();
q.pop();
FOREACH(i, lmt[v])
{
deg[*i]--;
maxn[*i] = max(maxn[*i], ans[v]);
if(chk[*i] == 1 && deg[*i] == 0)
{
ans[*i] = max(dist[*i], maxn[*i]);
q.push(*i);
chk[*i] = 2;
}
}
FOREACH(i, g[v])
if(chk[i->first] == 0)
pq.push(status(i->first, ans[v] + i->second));
}
while(!pq.empty())
{
status beg = pq.top();
pq.pop();
if(!chk[beg.v])
{
dist[beg.v] = beg.d;
if(deg[beg.v] == 0)
{
ans[beg.v] = max(dist[beg.v], maxn[beg.v]);
chk[beg.v] = 2;
q.push(beg.v);
break;
}
else
chk[beg.v] = 1;
}
}
}
printf("%I64d\n", ans[n - 1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: