思路
对于每个重要程度为2的战场,曹操的人数要大于袁绍的,枚举重要程度为2的战场,对于x战场曹操人数+1,则对应的袁绍战场y要+1,为了平衡这个影响,曹操要对y战场+1,然后又是袁绍……,不断将影响传递下去,直到传递到重要程度为0的战场,此时可以停止,因为重要程度为0的战场对胜负没有影响。记录传递的所有路径中的最小花费(最短路),即可知道当前枚举的战场的最小花费,枚举所有重要程度为2的战场,使得它们的曹操人数都等于袁绍人数+1即可。
这样跑显然会T,我们建反图,建新点空边连重要程度为0的点,然后对新点跑dijkstra获得到达每个重要程度为2的点的最短路,然后累加起来即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const ll INF = 1e13 + 10;
int x[maxn], y[maxn], c[maxn], w[maxn];
struct Edge{
int from, to, dis;
Edge(int from, int to, int dis):from(from), to(to), dis(dis){}
};
struct Node{
int dis, x;
Node(int dis, int x):dis(dis), x(x){}
bool operator < (const Node &a) const{
return dis > a.dis;
}
};
bool vis[maxn];
ll dis[maxn];
vector <Edge> G[maxn];
priority_queue <Node> que;
ll dijkstra(int n){
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++){
if(w[i] == 0){
que.push(Node(0, i));
dis[i] = 0;
}else
dis[i] = INF;
}
while(!que.empty()){
Node x = que.top(); que.pop();
int u = x.x;
if(vis[u])
continue;
vis[u] = true;
for(int i = 0; i < G[u].size(); i++){
Edge &e = G[u][i];
if(dis[e.to] > dis[e.from] + e.dis){
dis[e.to] = dis[e.from] + e.dis;
que.push(Node(dis[e.to], e.to));
}
}
}
ll ans = 0;
for(int i = 1; i <= n; i++){
if(w[i] == 2){
if(dis[i] == INF)
return -1;
ans += dis[i];
}
}
return ans;
}
int main(){
int T, Case = 1; scanf("%d", &T);
while(T--){
int n, m; scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++)
G[i].clear();
for(int i = 1; i <= n; i++)
scanf("%d", &x[i]);
for(int i = 1; i <= n; i++)
scanf("%d", &y[i]);
for(int i = 1; i <= n; i++)
scanf("%d", &c[i]);
for(int i = 1; i <= m; i++)
scanf("%d", &w[i]);
for(int i = 1; i <= n; i++)
G[y[i]].push_back(Edge(y[i], x[i], c[i]));
ll ans = dijkstra(m);
printf("Case #%d: %lld\n", Case++, ans);
}
return 0;
}