拓扑排序,从上往下回溯,挺好奇差分约束为啥就不对。拓扑排序有明显的优先级。

#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; typedef long long ll; typedef double db; const int N=1e4+50; vector<int>e[N]; int n,m; int in[N],a[N]; int topo(){ int cnt=0; queue<int>Q; for(int i=1;i<=n;i++)if(in[i]==0)cnt++,Q.push(i); while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=0;i<e[u].size();i++){ int v=e[u][i];--in[v]; if(!in[v]){ Q.push(v),cnt++; a[v]=max(a[v],a[u]+1); } } } if(cnt<n)return -1; int sum=0; for(int i=1;i<=n;i++)sum+=888+a[i]; return sum; } int main(){ while(~scanf("%d %d",&n,&m)){ memset(in,0,sizeof in); memset(a,0,sizeof a); for(int i=1;i<=n;i++)e[i].clear(); for(int i=1,u,v;i<=m;i++){ scanf("%d %d",&u,&v); e[v].pb(u);in[u]++; } cout<<topo()<<endl; } // system("pause"); return 0; }
G - G
带权并查集,维护一个sum数组,和move数组,
当移动时,把两堆移到一起,
查询时,找出当前节点的根,记录次数。
这样维护一个并查集,根节点move必然为0.
然后一个点的移动次数必然是到根节点的路径次数和。
然后每次find其实就是把当前节点和根接到一起。

#include<cstdio> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; typedef long long ll; typedef double db; const int N=1e4+50; int fa[N],sum[N],move[N]; int n; void init(){ for(int i=1;i<=n;i++)fa[i]=i,move[i]=0,sum[i]=1; } int find(int x){ if(fa[x]==x)return x; else { int t=fa[x]; fa[x]=find(fa[x]); move[x]+=move[t]; return fa[x]; } } void build(int u,int v){ int du=find(u); int dv=find(v); if(du!=dv){ fa[du]=dv; sum[du]=sum[dv]=sum[du]+sum[dv]; move[du]++; } } int main(){ int t,q,cas=0; char op; scanf("%d",&t); while(t--){ scanf("%d %d",&n,&q); printf("Case %d: ",++cas); init(); for(int i=1,u,v;i<=q;i++){ getchar(); scanf("%c",&op); if(op=='T'){ scanf("%d %d",&u,&v); build(u,v); } else { scanf("%d",&u); int du=find(u); printf("%d %d %d ",du,sum[du],move[u]); } } } // system("pause"); return 0; }
H - H
对于一个给定的图,最小点覆盖等于最大匹配,最大独立集等于最小点覆盖,题目让求最大独立集,实际上就是最大匹配。
先用floyd求闭包,然后求一遍最大匹配,每次找增广路是match[ v ],

#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; typedef long long ll; typedef double db; const int N=1e2+50; int gp[N][N]; int match[N],vis[N]; int n,m; void floyd(){ for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ gp[i][j]|=gp[i][k]&gp[k][j]; } } } } bool findpath(int u){ for(int i=1;i<=n;i++){ if(gp[u][i]&&!vis[i]){ vis[i]=1; if(!match[i]||findpath(match[i])){ match[i]=u; return 1; } } } return 0; } void init(){ memset(gp,0,sizeof gp); memset(match,0,sizeof match); // for(int i=1;i<=n;i++){ // for(int j=1;j<=n;j++){ // gp[i][j]=0; // match[i]=0; // } // } } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d %d",&n,&m); init(); for(int i=1,u,v;i<=m;i++){ scanf("%d %d",&u,&v); gp[u][v]=1; } floyd(); int sum=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); if(findpath(i))sum++; } printf("%d ",n-sum); } // system("pause"); return 0; }
L - L
对于一颗给定的最小生成树,当你选择s个点使得他们之间互相联通时,实际上会去掉 s -1 条边,贪心取最大即可。

#include<cstdio> #include<vector> #include<cmath> #include<algorithm> using namespace std; #define pb push_back const int N=5e2+50; typedef double db; // db eps=1e-9; int fa[N]; struct point{db x,y;}P[N]; struct edge{ int u,v;db w; edge(int a,int b,db c){ u=a;v=b;w=c; } }; vector<edge>e,ans; db dis(point a,point b){return sqrt( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) );} bool cmp(edge a,edge b){ return a.w<b.w; } int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void build(int x,int y){int dx=find(x),dy=find(y);if(dx!=dy)fa[dx]=dy;} int s,n; void init(){ for(int i=1;i<=n;i++)fa[i]=i; e.clear();ans.clear(); } void solve(){ for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ db d=dis(P[i],P[j]); e.pb(edge(i,j,d)); } } sort(e.begin(),e.end(),cmp); for(int i=0;i<e.size();i++){ int u=e[i].u,v=e[i].v; // db w=e[i].w; if(find(u)==find(v))continue; build(u,v); ans.pb(e[i]); } // for(int i=0;i<ans.size();i++)cout<<ans[i].w<<endl // cout<<ans.size()<<endl; sort(ans.begin(),ans.end(),cmp); if(n-s-1>=0)printf("%.2lf ",ans[n-s-1].w); else printf("%.2lf",0); } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d %d",&s,&n); init(); for(int i=1;i<=n;i++)scanf("%lf %lf",&P[i].x,&P[i].y); solve(); } // system("pause"); return 0; }