Gym - 100923B Por Costel and the Algorithm (最短路Dijkstra + 优先队列 +路径记录)

Por Costel and the Algorithm

 

Even though he isn't a student of computer science, Por Costel the pig has started to study Graph Theory. Today he's learning about Bellman-Ford, an algorithm that calculates the minimum cost path from a source node (for instance, node 1) to all the other nodes in a directed graph with weighted edges. Por Costel, utilizing his scarce programming knowledge has managed to scramble the following code in C++, a variation of the Bellman-Ford algorithm:

You can notice a lot of deficiencies in the above code. In addition to its rudimentary documentation, we can see that Por Costel has stored this graph as an array of edges (the array ). An edge is stored as the triplet  signifying an edge that spans from  to  and has weight . But even worse is the fact that the algorithm is SLOW!

As we want our hooved friend to walk away with a good impression about computer science, we want his code to execute as FAST as possible. In order to do so, we can modify the order of edges in the array  so that the while loop executes a small number of times.

Given a directed graph of  nodes and  edges, you are asked to produce an ordering of the edges such that the Bellman-Ford algorithm written by Por Costel should finish after at most two iterations of the while loop(that is, the program should enter the while loop at most twice).

Input

The first line of the file algoritm.in will contain an integer  , the number of test cases.

Each of the  test cases has the following format: on the first line, there are two numbers  and  (), the number of nodes and the number of edges in the graph respectively.

The next  lines describe the edges, each containing three integers signifying there is an edge from node  to node  with weight  ()

It is guaranteed that node  has at least one outgoing edge.

The graph may contain self loops and/or multiple edges.

Output

The output file algoritm.out should contain  lines representing the answers to each test case.

For each test case you should output a permutation of numbers from  to , representing the order of the edges you want in Por Costel's array of edges .

The edges are considered indexed by the order in which they are given in the input (the -th edge read is the edge with index ).

If there are multiple solutions, you are allowed to print any of them.

Example

Input

1
4 4
1 2 1
3 4 2
2 3 3
1 3 1

Output

1 4 2 3

题目链接:http://codeforces.com/gym/100923/problem/B

题目大意:n个节点m条单向边,要求把m条边重新排序,使得运行上面图片中代码是进入while循环不超过2次

要注意的是:这是一个单向边,单向边,单向边。我没仔细看,一直把它当成双向边,wa到自闭

思路:代码是求各点到1的最短路,进入while循环不能超过两次,也就是把所有的边遍历一次后就要得到1到所有点的最短路

那么也就是要把最短路径上的边放在前面,并且要把会影响后面节点的边放在前面,可以按照dfs遍历的顺序,

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<math.h>
using namespace std;
#define ll long long
const int N=200005;
const ll inf=(ll)1<<62;
int n,m,tot,cnt,cc;
int first[N],vis[N],path[N],a[N],b[N];
ll dis[N];
struct node
{
    int v,nex,id;
    ll w;
}e[N<<1];
struct qnode
{
    int v;
    ll w;
    qnode(int _v=0,ll _w=0):v(_v),w(_w){}
    bool operator<(const qnode &r)const
    {
        return w>r.w;
    }
};
void init()
{
    tot=cnt=cc=0;
    memset(first,-1,sizeof(first));
    memset(path,-1,sizeof(path));
    memset(b,0,sizeof(b));
}
void adde(int u,int v,ll w,int id)
{
    e[tot].v=v,e[tot].id=id;
    e[tot].w=w;
    e[tot].nex=first[u];
    first[u]=tot++;
}
void dij() //Dijkstra+优先队列
{
    for(int i=0;i<=n;i++)
    {
        vis[i]=0;
        dis[i]=inf;
    }
    priority_queue<qnode>q;
    dis[1]=0;
    q.push(qnode(1,0));
    qnode tmp;
    while(!q.empty())
    {
        tmp=q.top();
        q.pop();
        int u=tmp.v;
        if(vis[u]==1) continue;
        vis[u]=1;
        for(int i=first[u];~i;i=e[i].nex)
        {
            int v=e[i].v;
            if(!vis[v]&&dis[u]+e[i].w<dis[v])
            {
                dis[v]=dis[u]+e[i].w;
                q.push(qnode(v,dis[v]));
                path[v]=e[i].id;  //记录与v节点相连的路径
            }
        }
    }
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=first[u];~i;i=e[i].nex)
    {
        int v=e[i].v;
        if(vis[v]==0)
        {
            if(path[v]==e[i].id)
            {
                a[cnt++]=e[i].id;
                b[e[i].id]=1;
                dfs(v);
            }
        }
    }
}
void myin()
{
    freopen("algoritm.in","r",stdin);
    freopen("algoritm.out","w",stdout);
}
int main()
{
    myin();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        int u,v;
        ll w;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld",&u,&v,&w);
            adde(u,v,w,i);
        }
        dij();
        memset(vis,0,sizeof(vis));
        dfs(1);
        for(int i=0;i<cnt;i++)
            printf("%d ",a[i]);
        for(int i=1;i<=m;i++)
            if(!b[i]) printf("%d ",i);
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值