版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意
用所有的顶点( 注意是所有顶点! ), 构建一颗树, 如果不可以, 输出字符串,
否则输出构建的最小花费
不过这个题求边权的时候比较特殊,
某条边的边权 = 此边起点所到达的顶点及其所有子节点(不包括此起点)顶点值的和*此边的单位权值
仔细理解边权的求法, 比较绕, 但是看明白的确是很精妙
题解
这是一个巨坑 ! 巨坑 ! 巨坑 ! 重要的事情说三遍 ! wa了整整一页 !!!
INF 开 0x3f3f3f3f 会小了, 导致 wa !!! INF 开 0x3f3f3f3f 会小了, 导致 wa!!! INF 开 0x3f3f3f3f 会小了, 导致 wa!!!
dis数组 要开 long long , INF开 1e11 或者更大到 1e18, 19可能爆long long
附上样例 2 构建的图, 注意无向图
按题意要求, 计算最小花费时, 拆分合并一下同类项, 会神奇的发现
某条边的边权 = 此边所到达顶点的权值*1号节点到此顶点的最短路径
如下步骤,
那么, 我们只需要求出最短路以后, 对 dis[i]*value[i] 加和 即可
代码
Dijkstra+堆优化
// #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
class Dijkstra_HeapOptimize {
public:
static const int MAXN = 6e4+10, MAXM = 2e5+10;
static const ll INF = 1e11 ;
int N, M, S;
Dijkstra_HeapOptimize ( ) { };
Dijkstra_HeapOptimize ( int N, int M, int S ) : N(N), M(M), S(S) { };
struct EDGE {
int v, w, to;
}e[MAXM];
int head[MAXN]; ll dis[MAXN], cnt; bool vis[MAXN];
inline void add ( int u, int v, int w ) {
e[cnt].v = v, e[cnt].w = w, e[cnt].to = head[u]; head[u] = cnt++;
}
struct NODE {
int nd, w;
bool operator < ( const NODE& x )const {
return x.w < w;
}
};
std::priority_queue<NODE> q;
void ini ( int N, int M, int S ) {
this->N = N, this->M = M, this->S = S;
cnt = 0;
memset( head, -1, sizeof(head) );
// memset( dis, 0x3f, sizeof(dis) );
for ( int i = 1; i <= N; ++i ) dis[i] = INF;
dis[S] = 0;
memset( vis, false, sizeof(vis) );
while ( !q.empty() ) q.pop() ;
}
inline void run ( ) {
q.push ( (NODE){ S, 0 } );
while ( !q.empty ( ) ) {
register int u = q.top( ).nd;
q.pop ( );
if ( vis[u] ) continue;
vis[u] = true;
for ( int k = head[u]; k!=-1; k = e[k].to ) {
register int v = e[k].v, w = e[k].w;
if ( dis[v] > dis[u]+w ) {
dis[v] = dis[u]+w;
if ( !vis[v] ) {
q.push ( (NODE){ v, dis[v] } );
}
}
}
}
}
}dj;
int main ( ) { // freopen( "F:\\in\\.txt" , "r" , stdin );
int T,
n, m,
vm[dj.MAXN],
u, v, w;
sc( "%d", &T );
while ( T-- ) {
sc( "%d%d", &n, &m );
dj.ini( n, m, 1 );
for ( int i = 1; i <= n; ++i )
sc( "%d", &vm[i] );
for ( int i = 0; i < m; ++i ) {
// cin >> u >> v >> w;
sc( "%d%d%d", &u, &v, &w );
dj.add( u, v, w );
dj.add( v, u, w );
}
dj.run ( );
ll sum = 0;
bool flag = true;
for ( int i = 2; i <= n; ++i ) {
if ( dj.dis[i] == dj.INF ) {
flag = false;
break;
}
sum += dj.dis[i] * vm[i];
}
if ( flag ) pf( "%lld\n", sum );
else puts( "No Answer" );
}
return 0 ;
}
SPFA
// #include <bits/stdc++.h>
#include <cstdio>
#include <queue>
#include <cstring>
#define sc scanf
#define pf printf
using namespace std;
typedef long long ll;
class SPFA {
public:
static const int MAXN = 6e4+10, MAXM = 2e5+10;
static const ll INF = 1e15 ;
int n, m, s;
struct EDGE {
int v, w, to;
}e[MAXM];
int head[MAXN], cnt;
ll dis[MAXN]; bool vis[MAXN];
inline void add ( int u, int v, int w ) {
e[cnt].v = v, e[cnt].w = w, e[cnt].to = head[u]; head[u] = cnt++;
}
int tim[MAXN];
queue<int> q;
void ini ( int n, int m, int s ) {
this->n = n; this->m =m, this->s = s;
cnt = 0;
memset ( head, -1, sizeof ( head ) );
// memset ( dis, 0x3f, sizeof ( dis ) );
for ( int i = 1; i <= n; ++i ) dis[i] = INF;
dis[s] = 0;
memset ( vis, false, sizeof ( vis ) );
while ( !q.empty ( ) ) q.pop ( );
memset ( tim, 0, sizeof (tim) );
}
void run ( ) {
q.push( s );
vis[s] = true;
tim[s] = 0;
while ( !q.empty ( ) ) {
int u = q.front ( );
q.pop ( );
vis[u] = false;
for ( int k = head[u]; k!=-1; k = e[k].to ) {
int v = e[k].v, w = e[k].w;
if ( dis[v] > dis[u]+w ) {
dis[v] = dis[u]+w;
tim[v] = tim[u]+1;
if ( !vis[v] ) q.push ( v ), vis[v] = true;
}
}
}
}
}sp;
int main ( ) {
int T,
n, m,
vm[sp.MAXN],
u, v, w;
sc( "%d", &T );
while ( T-- ) {
sc( "%d%d", &n, &m );
sp.ini( n, m, 1 );
for ( int i = 1; i <= n; ++i )
sc( "%d", &vm[i] );
for ( int i = 0; i < m; ++i ) {
// cin >> u >> v >> w;
sc( "%d%d%d", &u, &v, &w );
sp.add( u, v, w );
sp.add( v, u, w );
}
sp.run ( );
ll sum = 0;
bool flag = true;
for ( int i = 2; i <= n; ++i ) {
if ( sp.dis[i] == sp.INF ) {
flag = false;
break;
}
sum += sp.dis[i] * vm[i];
}
if ( flag ) pf( "%lld\n", sum );
else puts( "No Answer" );
}
return 0;
}
再附上某人一个乱七八糟的 vector模拟邻接表实现 SPFA
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 1e12
using namespace std;
typedef long long ll;
const int MAX = 5e4+10;
struct edge{
int to,w;
//边:起点 from ,终点 to,权值 w ,from 并没有用到, e[i] 的 i 就是 from
};
vector<edge>e[MAX]; // e[i] : 存第 i 个节点连接的所有边
int n,m;
ll aa[MAX]; //存每个节点的权值
//int pre[MAX];
//记录前驱节点.pre[x] = y,在最短路径上,节点 x 的前一个结点是 y
int spfa(int s){
ll dis[MAX]; //记录所有结点到起点的距离
bool inq[MAX]; //inq[i] = true 表示节点 i 在队列中
// int Neg[MAX]; //判断负圈(Negative loop)
// memset(Neg,0,sizeof(Neg));
// Neg[s] = 1;
for(int i = 1; i <= n; i++){ //初始化
dis[i] = INF;
inq[i] = false;
}
dis[s] = 0; //起点到自己的距离是 0
queue<int>Q;
while(!Q.empty()) Q.pop();
Q.push(s);
inq[s] = true; //起点入队列
while(!Q.empty()){
int u = Q.front();
Q.pop(); //队列出队
inq[u] = false;
for(int i = 0; i < e[u].size(); i++){ //检查节点 u 的所有邻居
int v = e[u][i].to,w = e[u][i].w;
if(dis[u] + w < dis[v]){ //u 的第 i 个邻居 v, 他借道 u 到 s 更近
dis[v] = dis[u] + w; //更新第 i 个邻居到 s 的距离
if(!inq[v]){ //第 i 个邻居更新状态了,但是他不在队列中,把它放进队列
inq[v] = true;
Q.push(v);
// Neg[v]++;
// if(Neg[v] > n) return 1; //出现负圈
}
}
}
}
int flag = 0;
for(int i = 1; i <= n; i++){
if(dis[i] == INF){
flag = 1;
break;
}
}
if(flag == 1){
printf("No Answer\n");
}
else{
ll sum = 0;
for(int i = 1; i <= n; i++){
sum += dis[i]*aa[i];
}
printf("%lld\n",sum);
}
return 0;
}
int main(){
int T,a,b,c;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; i++){
e[i].clear();
}
for(int i = 1; i <= n; i++){
scanf("%lld",&aa[i]);
}
for(int i = 1; i <= m; i++){
scanf("%d %d %d",&a,&b,&c);
e[a].push_back( (edge) { b,c} ); //结点 a 的邻居,都放在 node[a] 里
e[b].push_back( (edge) { a,c} );
}
spfa(1); //起点是1
}
return 0;
}
来自 poj discuss的数据
/* 提供水数据。。。
Posted by squarefk at 2012-01-26 01:42:04 on Problem 3013
INPUT:
3
2 1
3 1
2 2 3
4 10
7 5 1 10
1 2 9
4 4 2
2 3 5
1 1 1
2 1 4
1 2 1
4 3 5
2 1 6
2 4 9
3 4 4
8 60
6 12 1 6 19 6 6 16
4 3 160
5 7 87
7 1 46
4 5 190
3 4 156
2 8 96
3 2 193
4 8 8
8 4 126
2 2 52
4 2 68
1 4 119
6 8 182
5 3 188
1 1 160
6 2 8
3 6 171
3 7 147
7 5 46
1 3 43
3 6 36
7 7 103
5 4 69
5 4 128
3 8 40
6 5 118
1 5 51
8 2 35
6 6 108
1 5 80
4 2 5
1 3 84
3 6 34
6 1 94
3 4 112
7 3 57
7 8 179
4 7 138
3 6 74
4 4 161
2 1 81
8 6 7
3 1 73
2 2 58
4 7 35
6 6 79
3 6 40
3 4 136
2 8 178
1 3 127
5 7 137
4 2 123
8 7 163
7 4 124
7 3 20
8 8 200
6 1 164
2 5 119
5 2 99
2 8 171
OUTPUT:
No Answer
111
4536
*/