题意:
给一棵树,边权未知,现在给m组约束,每组约束给出从u到v路径中的最小值,现在让你给出一组边权,使得符合之前的约束,不能给出输出-1
思路:
因为n较小,对于每组约束我们可以直接暴力修改路径上的权值,如果边的权值小于当前约束的最小值,则将权值修改,最后再根据每组约束暴力走一遍路径看路径是否满足要求,如果不满足则输出-1,最后还得对那些没有修改过的边随意赋值
#include<iostream> #include<algorithm> #include<vector> #include<cstring> #define inf 0x3f3f3f3f using namespace std; const int maxn=5005; int id[maxn][maxn],edge[maxn][maxn],fa[maxn],f[maxn],dep[maxn]; //id记录从i到j这条边的编号,edge记录边的权值,fa记录i的父亲是谁,f记录边的权值 ,dep记录深度 vector<int> a[maxn]; int from[maxn],to[maxn],mi[maxn]; int n,m,u,v,w; void dfs(int x,int p)//处理出父亲与深度 { fa[x]=p,dep[x]=dep[p]+1; for(int i=0;i<a[x].size();i++) if(a[x][i]!=p) dfs(a[x][i],x); } void dfs2(int x,int p) { for(int i=0;i<a[x].size();i++){ if(a[x][i]!=p){ int to=a[x][i]; f[id[x][to]]=edge[x][to]; dfs2(a[x][i],x); } } } void solve() { scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&from[i],&to[i],&mi[i]); if(dep[from[i]]<dep[to[i]]) swap(from[i],to[i]); int k1=from[i],k2=to[i],mini=mi[i]; while(dep[k1]!=dep[k2]){ int p=fa[k1]; if(edge[p][k1]<=mini) edge[p][k1]=edge[k1][p]=mini; k1=p; } while(k1!=k2){ int p1=fa[k1],p2=fa[k2]; if(edge[p1][k1]<=mini) edge[p1][k1]=edge[k1][p1]=mini; if(edge[p2][k2]<=mini) edge[p2][k2]=edge[k2][p2]=mini; k1=p1,k2=p2; } } for(int i=1;i<=m;i++){ int x=inf; int k1=from[i],k2=to[i],mini=mi[i]; if(dep[k1]<dep[k2]) swap(k1,k2); while(dep[k1]!=dep[k2]){ int p=fa[k1]; x=min(x,edge[p][k1]); k1=p; } while(k1!=k2){ int p1=fa[k1],p2=fa[k2]; x=min(x,edge[p1][k1]); x=min(x,edge[p2][k2]); k1=p1,k2=p2; } if(x!=mini){ cout<<-1<<endl;return;} } dfs2(1,0); for(int i=1;i<n;i++){ if(!f[i]) cout<<100000<<" "; else cout<<f[i]<<" "; } } int main() { scanf("%d",&n); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); a[u].push_back(v); a[v].push_back(u); id[u][v]=id[v][u]=i; } dfs(1,0); solve(); return 0; }
原文地址:https://www.cnblogs.com/overrate-wsj/p/12267197.html
时间: 2024-11-08 16:10:44