ASC22 C Important Roads|| ACdream 1415 【两次spfa+无向图割边】

来源:互联网 发布:java入门书 编辑:程序博客网 时间:2024/06/06 05:50

Important Roads

Special JudgeTime Limit: 20000/10000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others)
SubmitStatisticNext Problem

Problem Description

      The city where Georgie lives has n junctions some of which are connected by bidirectional roads.
      Every day Georgie drives from his home to work and back. But the roads in the city where Georgie lives are very bad, so they are very often closed for repair. Georgie noticed that when some roads are closed he still can get from home to work in the same time as if all roads were available.

      But there are such roads that if they are closed for repair the time Georgie needs to get from home to work increases, and sometimes Georgie even cannot get to work by a car any more. Georgie calls such roads important.
      Help Georgie to find all important roads in the city.

Input

      The first line of the input file contains n and m — the number of junctions and roads in the city where Georgie lives, respectively (2 ≤ n ≤ 20 000, 1 ≤ m ≤ 100 000). Georgie lives at the junction 1 and works at the junction n.

      The following m lines contain information about roads. Each road is specified by the junctions it connects and the time Georgie needs to drive along it. The time to drive along the road is positive and doesn’t exceed 100 000. There can be several roads between a pair of junctions, but no road connects a junction to itself. It is guaranteed that if all roads are available, Georgie can get from home to work.

Output

      Output l — the number of important roads — at the first line of the output file. The second line must contain l numbers, the numbers of important roads. Roads are numbered from 1 to m as they are given in the input file.

Sample Input

6 71 2 12 3 12 5 31 3 23 5 12 4 15 6 2

Sample Output

25 7

Source

Andrew Stankevich Contest 22

/**给出无向连通图(有重边),给出起点和终点,问关键边的个数及具体编号*关键边:如果删掉这条边,就可以使得从起点到终点的最短距离变长或者不能到达,那么此边为关键边*做法:分别从起点和终点各跑一次【spfa】,找到从起点到终点的最短路上可能存在的边,建图,求此图的割边,即为所求*【带重边】的无向图求桥,spfa要用优先队列优化*/#include<stdio.h>#include<algorithm>#include<queue>#include<vector>#include<iostream>#include<map>#include<utility>#include<cstring>using namespace std;#define maxn 20050#define inf 0x3f3f3f3fint dis[maxn][2],head[maxn],ind;bool inq[maxn];int n,mmin,m;int x[maxn*10],y[maxn*10],z[maxn*10];//这里数组开小导致一致RE,也是醉了struct node{//u起点,v终点,d距离,id边的标号int u,v,d,id;int next;}edge[200005];void addedge(int s,int t,int val,int id){edge[ind].u = s;edge[ind].v = t;edge[ind].d = val;edge[ind].id = id;edge[ind].next = head[s];head[s] = ind++;edge[ind].u = t;edge[ind].v = s;edge[ind].d = val;edge[ind].id = id;edge[ind].next = head[t];head[t] = ind++;}struct Node  {      int u, d;      Node(int u = 0, int d = 0) : u(u), d(d) {}      bool operator<(const Node & cmp) const      {          return d > cmp.d;      }  }; void spfa(int start,int ord){//求最短路 用dijkstra还是spfa都行,不过一定要用优先队列优化,否则会T的很惨memset(inq,0,sizeof(inq));priority_queue<Node> que;      que.push(Node(start, 0));  Node x;    while(!que.empty())      {          x = que.top();          que.pop();            if(inq[x.u]) continue;          inq[x.u] = true, dis[x.u][ord] = x.d;            for (int i = head[x.u]; i != -1 ; i = edge[i].next)if(!inq[edge[i].v])  que.push(Node(edge[i].v, x.d + edge[i].d));      } //if(ord==0)printf("%d\n",dis[n][ord]);//if(ord==1)printf("%d\n",dis[1][ord]);} int bri[200005],num;void build(){//重新建图,选择出边集中 在起点到终点的最短路上的边加入图中。ind=0;memset(head,-1,sizeof(head));mmin = dis[n][0];for (int i = 1; i <= m; i++){int u = x[i], v = y[i],w = z[i];if(dis[u][0]+w+dis[v][1]==mmin || dis[u][1]+dis[v][0]+w == mmin){addedge(u,v,w,i);}}}int p[maxn],low[maxn],dfn[maxn],Time;//时间戳 void init(){ind = 0;memset(head,-1,sizeof(head));}void geb_init(){Time = 0;memset(dfn,0,sizeof(dfn));memset(p,0,sizeof(p));}void Tarjan(int cur, int from) {  //带重边的无向图求割边【还没懂为嘛,不过还是先用着    low[cur] = dfn[cur] = ++Time;  bool flag = true;for (int i=head[cur];i!=-1;i=edge[i].next) {          int v = edge[i].v; int nid = edge[i].id;        if (v == from && flag){flag = false;continue;   }        if (!dfn[v]) {              Tarjan(v, cur);                   if (low[v] < low[cur]) low[cur] = low[v];              if (low[v] > dfn[cur]) {  bri[num++] = nid;             }          } else if (low[cur] > dfn[v]) low[cur] = dfn[v];      }  }  void CUT_EDGE(){build();geb_init();//Tarjan(1,0);for(int i = 1; i <= n; i++)            if(!dfn[i]) Tarjan(i,-1);printf("%d\n",num);for (int i = 0; i < num; i++){printf("%d",bri[i]);if(i==num-1)printf("\n");else printf(" ");}}int main(){//freopen("important.in","r",stdin);//freopen("important.out","w",stdout);while(~scanf("%d%d",&n,&m)){num = 0;init();int s,t,d;for (int i = 1; i <= m; i++){scanf("%d%d%d",&s,&t,&d);x[i] = s;y[i] = t;z[i] = d;addedge(s,t,d,i);}spfa(1,0);spfa(n,1);CUT_EDGE();}return 0;}

换上汉神的模板,也能过= =

#include<stdio.h>#include<algorithm>#include<queue>#include<vector>#include<iostream>#include<map>#include<utility>#include<cstring>using namespace std;#define maxn 20005#define inf 0x3f3f3f3fint dis[maxn][2],head[maxn],ind;bool inq[maxn];int n,mmin,m;int x[maxn*10],y[maxn*10],z[maxn*10];struct node{    //u起点,v终点,d距离,id边的标号    int u,v,d,id;    int next;}edge[200005];void addedge(int s,int t,int val,int id){    edge[ind].u = s;    edge[ind].v = t;        edge[ind].d = val;    edge[ind].id = id;  edge[ind].next = head[s];    head[s] = ind++;      edge[ind].u = t;    edge[ind].v = s;        edge[ind].d = val;    edge[ind].id = id;  edge[ind].next = head[t];    head[t] = ind++;}struct Node {     int u, d;     Node(int u = 0, int d = 0) : u(u), d(d) {}     bool operator<(const Node & cmp) const     {         return d > cmp.d;     } };void spfa(int start,int ord){    memset(inq,0,sizeof(inq));    priority_queue<Node> que;     que.push(Node(start, 0));     Node x;    while(!que.empty())     {         x = que.top();         que.pop();            if(inq[x.u]) continue;         inq[x.u] = true, dis[x.u][ord] = x.d;            for (int i = head[x.u]; i != -1 ; i = edge[i].next)            if(!inq[edge[i].v])                 que.push(Node(edge[i].v, x.d + edge[i].d));     }    //if(ord==0)printf("%d\n",dis[n][ord]);    //if(ord==1)printf("%d\n",dis[1][ord]);}  struct Bridge {    int u, v, id;    Bridge(int x,int y,int z){        u=x,v=y,id=z;    }};  //用来记录桥queue<Bridge>bri;  node edge2[200005];int ind2,head2[maxn];void addedge2(int s,int t,int val,int id){    edge2[ind2].u = s;    edge2[ind2].v = t;      edge2[ind2].d = val;    edge2[ind2].id = id;    edge2[ind2].next = head2[s];    head2[s] = ind2++;      edge2[ind2].u = t;    edge2[ind2].v = s;      edge2[ind2].d = val;    edge2[ind2].id = id;    edge2[ind2].next = head2[t];    head2[t] = ind2++;}void build(){    ind2=0;    memset(head2,-1,sizeof(head2));    mmin = dis[n][0];    for (int i = 1; i <= m; i++)    {        int u = x[i], v = y[i],w = z[i];        if(dis[u][0]+w+dis[v][1]==mmin || dis[u][1]+dis[v][0]+w == mmin){            addedge2(u,v,w,i);        }    }}int p[maxn],low[maxn],dfn[maxn],Time;//时间戳void init(){    ind = 0;    memset(head,-1,sizeof(head));    while (!bri.empty())bri.pop();}void geb_init(){    Time = 0;    memset(dfn,0,sizeof(dfn));    memset(p,0,sizeof(p));}void Tarjan(int cur, int from) {    low[cur] = dfn[cur] = Time++;    for (int i=head2[cur];i!=-1;i=edge2[i].next) {        int v = edge2[i].v;        int nid = edge2[i].id;        if (nid == from) continue;  //注意一下这里.   如果是重边的话,改成:if (edge[p].id == from) continue; 给tarjan传参数from的时候,传递的是当前边的id。        if (!dfn[v]) {            Tarjan(v, nid);       //多重边:tarjan(v, edge[p].id);            if (low[v] < low[cur]) low[cur] = low[v];            if (low[v] > dfn[cur]) {                Bridge tmp(cur,v,nid);                bri.push(tmp);            }        } else if (low[cur] > dfn[v]) low[cur] = dfn[v];    }}void CUT_EDGE(){    build();    geb_init();    Tarjan(1,0);    printf("%u\n",bri.size());    Bridge tmp(0,0,0);    while (!bri.empty())    {        tmp = bri.front();        bri.pop();        //printf("%d %d %d\n",tmp.u,tmp.v,tmp.id);        printf("%d",tmp.id);        if(bri.empty())puts("");        else printf(" ");    }}int main(){freopen("important.in","r",stdin);freopen("important.out","w",stdout);    while(~scanf("%d%d",&n,&m)){        init();        int s,t,d;        for (int i = 1; i <= m; i++)        {            scanf("%d%d%d",&s,&t,&d);            x[i] = s;            y[i] = t;            z[i] = d;            addedge(s,t,d,i);        }        spfa(1,0);        spfa(n,1);        CUT_EDGE();    }    return 0;}


0 0