给你一棵树,树上有点权和边权,让你选择起点S到终点T使得T-S-sum最大。(sum是S到T的距离)输出这个最大值。
这是2017ACM-ICPC沈阳的网络赛的1008题,这里不得不吐槽一下这个网络赛的体验真的很差,好多题的数据都很弱,各种暴力都能过。。。还有个题最差交 210 必过,直接导致暴力交题,最后OJ都爆了。。。相信很多做过网络赛的都心有余悸。。。
这题比赛的时候没做出来,其实转化一下就是求最长路的题了。我们新建一个点作为源点(我选的是0),然后建源点到n个点的有向边,边权为-w[i](w[i]是i点的点权)。之后新建一个点作为汇点(我选的是n+1),建n个点到汇点的有向边,边权为w[i]。最后求源点到汇点的最长路即可。这里用SPFA和Dijkstra(优先队列优化)均可。
#include
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;
int dist[maxn],in_queue[maxn];
bool vis[maxn];
int n;
struct Edge{
int to,w,next;
}edge[maxn<<2];
int head[maxn],tot;
void add_edge(int u,int v,int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
bool SPFA()
{
int cur,next;
queue<int> q;
vis[0] = true;
in_queue[0]++;
dist[0] = 0;
q.push(0);
while(!q.empty())
{
cur = q.front(),q.pop();
vis[cur]=false;
for(int i=head[cur];i!=-1;i=edge[i].next)
{
int to = edge[i].to;
int w = edge[i].w;
if(dist[to]if(!vis[to])
{
in_queue[to]++;
if(in_queue[to]>=n+2) return false;
q.push(to);
vis[to] = true;
}
}
}
}
return true;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
tot=0;
memset(head,-1,sizeof(head));
memset(dist,-INF,sizeof(dist));
memset(vis,false,sizeof(vis));
memset(in_queue,0,sizeof(in_queue));
int u,v,w;
for(int i=1;i<=n;i++)
{
scanf("%d",&w);
add_edge(0,i,-w);
add_edge(i,n+1,w);
}
for(int i=1;iscanf("%d%d%d",&u,&v,&w);
add_edge(u,v,-w);
add_edge(v,u,-w);
}
SPFA();
printf("%d\n",dist[n+1]);
}
return 0;
}
#include
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;
typedef pair<int,int> P;
int dist[maxn];
int n;
struct Edge{
int to,w,next;
}edge[maxn<<2];
int head[maxn],tot;
void add_edge(int u,int v,int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void Dijkstra()
{
priority_queue pq;
P p;
dist[0]=0;
pq.push(P(dist[0],0));
while(!pq.empty())
{
p = pq.top(),pq.pop();
int u = p.second;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
int w = edge[i].w;
if(dist[v]int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
tot=0;
memset(head,-1,sizeof(head));
memset(dist,-INF,sizeof(dist));
int u,v,w;
for(int i=1;i<=n;i++)
{
scanf("%d",&w);
add_edge(0,i,-w);
add_edge(i,n+1,w);
}
for(int i=1;iscanf("%d%d%d",&u,&v,&w);
add_edge(u,v,-w);
add_edge(v,u,-w);
}
Dijkstra();
printf("%d\n",dist[n+1]);
}
return 0;
}
上面是Dijkstra代码的,下面是SPFA代码的,这题是SPFA跑得快内存也少。