Breaking Good
Breaking Good is a new video game which a lot of gamers want to have. There is a certain level in the game that is really difficult even for experienced gamers.
Walter William, the main character of the game, wants to join a gang called Los Hermanos (The Brothers). The gang controls the whole country which consists of n cities with m bidirectional roads connecting them. There is no road is connecting a city to itself and for any two cities there is at most one road between them. The country is connected, in the other words, it is possible to reach any city from any other city using the given roads.
The roads aren't all working. There are some roads which need some more work to be performed to be completely functioning.
The gang is going to rob a bank! The bank is located in city 1. As usual, the hardest part is to escape to their headquarters where the police can't get them. The gang's headquarters is in city n. To gain the gang's trust, Walter is in charge of this operation, so he came up with a smart plan.
First of all the path which they are going to use on their way back from city 1 to their headquarters n must be as short as possible, since it is important to finish operation as fast as possible.
Then, gang has to blow up all other roads in country that don't lay on this path, in order to prevent any police reinforcements. In case of non-working road, they don't have to blow up it as it is already malfunctional.
If the chosen path has some roads that doesn't work they'll have to repair those roads before the operation.
Walter discovered that there was a lot of paths that satisfied the condition of being shortest possible so he decided to choose among them a path that minimizes the total number of affected roads (both roads that have to be blown up and roads to be repaired).
Can you help Walter complete his task and gain the gang's trust?
The first line of input contains two integers n, m (2 ≤ n ≤ 105, ), the number of cities and number of roads respectively.
In following m lines there are descriptions of roads. Each description consists of three integers x, y, z (1 ≤ x, y ≤ n, ) meaning that there is a road connecting cities number x and y. If z = 1, this road is working, otherwise it is not.
In the first line output one integer k, the minimum possible number of roads affected by gang.
In the following k lines output three integers describing roads that should be affected. Each line should contain three integers x, y, z (1 ≤ x, y ≤ n, ), cities connected by a road and the new state of a road. z = 1 indicates that the road between cities x and y should be repaired and z = 0 means that road should be blown up.
You may output roads in any order. Each affected road should appear exactly once. You may output cities connected by a single road in any order. If you output a road, it's original state should be different from z.
After performing all operations accroding to your plan, there should remain working only roads lying on some certain shortest past between city 1 and n.
If there are multiple optimal answers output any.
2 1 1 2 0
1 1 2 1
4 4 1 2 1 1 3 0 2 3 1 3 4 1
3 1 2 0 1 3 1 2 3 0
8 9 1 2 0 8 3 0 2 3 1 1 4 1 8 7 0 1 5 1 4 6 1 5 7 0 6 8 0
3 2 3 0 1 5 0 6 8 1
In the first test the only path is 1 - 2
In the second test the only shortest path is 1 - 3 - 4
In the third test there are multiple shortest paths but the optimal is 1 - 4 - 6 - 8
在一个有n个城市m条道路的国家,有一个犯罪团伙要去抢劫银行,银行在城市1,犯罪团伙在城市n,
walter的任务是在城市1和城市n之间选择一个最短路径,当有多个最短路径的时候选择影响值最小的 ,
为0的道路是指未工作的,为1的道路是指修好的,walter在选择好最短路径后,要修复好最短路径上
未工作的路,破坏其他路径上工作的路径,
影响值= 修复+破化的道路,修复的道路=最短路径数-最短路径上工作的路径,
破化的道路=工作的总道路-最短路径上工作的道路 ,所以要使影响值最小应该使得最短路径上面工作的道路最多,
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define INF 10000005
using namespace std;
struct Edge{ //使用链式前向星进行存储
int u,v,w,z,next;
}edge[200005];
int head[200005],dis[200005],vis[200005],path[200005],n,m,sum,cnt,value[200005];
//head[i]表示以i为起点的边,dis[]求距离,path[]求路径,value[]求影响值
//影响值是指修复和破化的道路的和
void spfa(){
queue<int> q;
for(int i = 0; i <= n; i ++){ //对各个数组进行初始化
dis[i] = INF;
value[i] = 0;
vis[i] = 0;
path[i] = -1;
}
q.push(1);
dis[1] = 0; //本身距离为0
while(!q.empty()){
int k = q.front();
q.pop();
vis[k] = 0; //出队列后元素不在队列中
for(int i = head[k]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(dis[v] > dis[k] + edge[i].w || (dis[v] == dis[k] + edge[i].w && value[v] < value[k] + edge[i].z)){
//选择最短路径或者相同的距离的路径但影响值大的
dis[v] = dis[k] + edge[i].w;
value[v] = value[k] + edge[i].z;
path[v] = k; //记录前驱结点
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i = 0; i <= n; i ++){
head[i] = -1;
}
int x,y,z;
cnt=0; sum=0;
for(int i = 1; i <= m; i ++){
scanf("%d%d%d",&x,&y,&z);
edge[cnt].u = x;
edge[cnt].v = y;
edge[cnt].w = 1; //表示道路的权值
edge[cnt].z = z; //表示路径的状况,是工作还是未工作
edge[cnt].next = head[x];//表示起点同为x的下一条边
head[x] = cnt ++;
edge[cnt].u = y;
edge[cnt].v = x;
edge[cnt].z = z;
edge[cnt].w = 1;
edge[cnt].next = head[y];
head[y] = cnt ++;
sum += z; //记录整个图的工作的路径的个数
}
spfa(); //求最短路径
int count = dis[n] - value[n] + sum - value[n];
//影响值=最短路径中的未工作的路径 + 其他路径中工作的路径
printf("%d\n",count);
memset(vis,0,sizeof(vis));
x = n;
while(x != 1){ //对最短路径中的顶点进行标记
vis[x] = 1;
x = path[x];
}
vis[1] = 1;
for(int i = 0; i < cnt; i += 2){
x = edge[i].u; y = edge[i].v;
if((!vis[x] || !vis[y]) && edge[i].z) //其他路径输出工作的路径
printf("%d %d 0\n",x,y);
if(vis[x] && vis[y] && !edge[i].z) //最短路径输出未工作的路径
printf("%d %d 1\n",x,y);
}
}
return 0;
}