hdu 5385 The path

 构造题

使用贪心法构造,因为保证有解,点2或n至少有一个直接与点1相连

上述结论可以用反证法证明。

假若2和n不直接与1相连,那么必存在点x直接与1相连,间接与2,n相连。这种情况下无论如何设置边权,都有d[x]<d[2]&&d[x]<d[n],与已知矛盾

那么可以按照每次添加两头的点与1相连,记添加时间为1到该点的最短路,边添加边计算边权

然后不在最短路树上的边权都设为n即可,这样不会使最短路树发生变化

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100008;
struct edge{
    int v,i;
};
int w[maxn];
vector<edge>    g[maxn];
int uni[maxn],dis[maxn];
void solve(int n)
{
    int v,idx,i;
    int left=2,right=n;
    dis[1]=0;int ti=0;
    while(left<right)
    {
        for(i=0;i<g[left].size();i++)
        {
            v=g[left][i].v;
            idx=g[left][i].i;
            if(uni[v]==1)
            {
                dis[left]=ti+1;
                w[idx]=dis[left]-dis[v];
                uni[left++]=1;
                ti++;
                break;
            }
        }
        if(left>=right)    break;
        for(i=0;i<g[right].size();i++)
        {
            v=g[right][i].v;
            idx=g[right][i].i;
            if(uni[v]==1)
            {
                dis[right]=ti+1;
                w[idx]=dis[right]-dis[v];
                uni[right--]=1;
                ti++;
                break;
            }
        }
    }
}
int main()
{
    int i,j,t,n,m,u,v;
    edge pp;
    //freopen("1006.in","r",stdin);
//    freopen("1011.txt","w",stdout);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            g[i].clear();
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            pp.i=i;
            pp.v=u;
            g[v].push_back(pp);
        }
        for(i=1;i<=n;i++)
            uni[i]=i;
        memset(w,-1,sizeof(w));
        solve(n);
        for(i=1;i<=m;i++)
        {
            if(w[i]==-1)
                printf("%d\n",n);
            else
                printf("%d\n",w[i]);
        }
    }
    return 0;
}

 

posted on 2015-08-15 09:33  此剑之势愈斩愈烈  阅读(229)  评论(0编辑  收藏  举报

导航