codevs 1269 匈牙利游戏

/*暴力+乱搞 55分(似乎只有暴力得分了)*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define maxn 1000010
using namespace std;
int n,m,num,head[maxn],dfn[maxn],low[maxn],s[maxn],top,f[maxn];
int sum,topt,c[maxn],dis[maxn],dis2[maxn],vis[maxn],pre[maxn];
int belong[maxn],cir[maxn],ans1=0x7fffffff,ans2=0x7fffffff,D,falg;
struct node
{
    int u,v,t,pre;
}e[maxn];
void Add(int from,int to,int dis)
{
    num++;
    e[num].u=from;
    e[num].v=to;
    e[num].t=dis;
    e[num].pre=head[from];
    head[from]=num;
}
void Tarjan(int x)
{
    low[x]=dfn[x]=++topt;
    s[++top]=x;f[x]=1;
    for(int i=head[x];i;i=e[i].pre)
      if(dfn[e[i].v]==0){Tarjan(e[i].v);low[x]=min(low[x],low[e[i].v]);}
      else if(f[e[i].v]==1)low[x]=min(low[x],dfn[e[i].v]);
    if(low[x]==dfn[x])
      {
          sum++;
          while(x!=s[top])
            {
                c[sum]++;f[s[top]]=0;
            belong[s[top]]=sum;top--;
          }
        c[sum]++;f[s[top]]=0;
        belong[s[top]]=sum;top--;
      }
}
void SPFA()
{
    queue<int>q;
    memset(dis,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0;vis[1]=1;q.push(1);
    while(!q.empty())
      {
          int k=q.front();q.pop();vis[k]=0;
          for(int i=head[k];i;i=e[i].pre)
            {
                int v=e[i].v;
                if(dis[v]>dis[k]+e[i].t)
                  {
                      dis[v]=dis[k]+e[i].t;pre[v]=k;
                      if(vis[v]==0){vis[v]=1;q.push(v);}
              }
          }
      }
}
void SPFA2(int si,int ti)
{
    queue<int>q;
    memset(dis2,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis2[1]=0;vis[1]=1;q.push(1);
    while(!q.empty())
      {
          int k=q.front();q.pop();vis[k]=0;
          for(int i=head[k];i;i=e[i].pre)
            {
                int v=e[i].v;
                if(si==k&&ti==v)continue;
                if(dis2[v]>dis2[k]+e[i].t)
                  {
                      dis2[v]=dis2[k]+e[i].t;
                      if(vis[v]==0){vis[v]=1;q.push(v);}
              }
          }
      }
}
void Dfs(int x,int d)
{
    if(d>ans1)return;
    if(x==n&&d!=dis[n])
      {
          ans1=min(ans1,d);
          return;
      }
    for(int i=head[x];i;i=e[i].pre)
      Dfs(e[i].v,d+e[i].t);
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y,z;
    for(int i=1;i<=m;i++)
      {
          scanf("%d%d%d",&x,&y,&z);
          if(x==1&&y==n)
          D=z;
          Add(x,y,z);
      }
    for(int i=1;i<=n;i++)
      if(dfn[i]==0)Tarjan(i);
    for(int i=1;i<=n;i++)
      if(c[belong[i]]>=2)cir[i]=1;
    SPFA();
    int p=n;
    while(p>1)
      {
          if(cir[p]==1)falg=1;p=pre[p];
      }
    if(falg)
      {
          Dfs(1,0);
          if(ans1==0x7fffffff)printf("-1\n");
        else printf("%d\n",ans1);
          return 0;
      }
    p=n;
    while(p>1)
      {
          SPFA2(pre[p],p);
          if(dis2[n]!=dis[n])ans2=min(ans2,dis2[n]);
          if(cir[p]==1)ans1=min(ans1,dis[n]+c[belong[p]]);
          p=pre[p];
      }
    if(D!=dis[n])ans1=min(ans1,D);
    if(ans2==0x7fffffff&&sum==0)printf("-1\n");
    else printf("%d\n",min(ans1,ans2));
    return 0; 
}
/*
正解. 正反跑spfa 记录每个节点的1跑过来的最短路和n跑过来的最短路
考试的时候想的是每个点的这两个值加起来 然后求此小值 
后来发现 样例都过不了.....
原因是 这里的dis数组的定义决定了会忽略一些边
所以 接着这个思路想下来 我们强制走某一条边
也就是我们枚举边 然后计算 disu + dis2v + uv 就是一条路径的长度
注意这里统计出来的数的个数不是路径数 因为同一条路径上的许多边都统计了一遍
但这里求的是严格次短路 这就很好的符合我们求出来的值 只需要找出第二小的不同的就好
也就是说 这种方法不能求次短路 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define maxn 200010
using namespace std;
int n,m,num,num2,head[maxn],head2[maxn],dis[maxn],dis2[maxn],vis[maxn],ans[maxn],l;
int ans1=707406378,ans2=707406378;
struct node
{
    int u,v,t,pre;
}e[maxn],e2[maxn];
void Add(int from,int to,int dis)
{
    num++;
    e[num].u=from;
    e[num].v=to;
    e[num].t=dis;
    e[num].pre=head[from];
    head[from]=num;
}
void Add2(int from,int to,int dis)
{
    num2++;
    e2[num].u=from;
    e2[num].v=to;
    e2[num].t=dis;
    e2[num].pre=head2[from];
    head2[from]=num2;
}
void SPFA()
{
    queue<int>q;
    memset(dis,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0;vis[1]=1;q.push(1);
    while(!q.empty())
      {
          int k=q.front();q.pop();vis[k]=0;
          for(int i=head[k];i;i=e[i].pre)
            {
                int v=e[i].v;
                if(dis[v]>dis[k]+e[i].t)
                  {
                      dis[v]=dis[k]+e[i].t;
                      if(vis[v]==0){vis[v]=1;q.push(v);}
              }
          }
      }
}
void SPFA2()
{
    queue<int>q;
    memset(dis2,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis2[n]=0;vis[n]=1;q.push(n);
    while(!q.empty())
      {
          int k=q.front();q.pop();vis[k]=0;
          for(int i=head2[k];i;i=e2[i].pre)
            {
                int v=e2[i].v;
                if(dis2[v]>dis2[k]+e2[i].t)
                  {
                      dis2[v]=dis2[k]+e2[i].t;
                      if(vis[v]==0){vis[v]=1;q.push(v);}
              }
          }
      }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y,z;
    for(int i=1;i<=m;i++)
      {
          scanf("%d%d%d",&x,&y,&z);
          Add(x,y,z);Add2(y,x,z);
      }
    SPFA();SPFA2();
    for(int i=1;i<=num;i++)
      {
          int u=e[i].u;int v=e[i].v;
          ans[++l]=dis[u]+dis2[v]+e[i].t;
      }
    sort(ans+1,ans+1+l);
    ans1=ans[1];
    for(int i=2;;i++)
      if(ans[i]!=ans1)
        {
          ans2=ans[i];break;
        }
    if(ans2>=0x7fffffff)printf("-1\n");
    else printf("%d\n",ans2);
    return 0;
}

 

posted @ 2016-08-05 15:21  一入OI深似海  阅读(138)  评论(0编辑  收藏  举报