HDU 5385 |
构造题
使用贪心法构造,因为保证有解,点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; }
时间: 2024-10-07 03:50:34