HZNU Training 23 for Zhejiang Provincial Competition 2020

C - C

 CodeForces - 653D 

 网络流,待补。

F - F

 HDU - 2647 

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

#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;
}
View Code

G - G

 HDU - 3635 

带权并查集,维护一个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;
}
View Code 

H - H

 计蒜客 - A1542 

对于一个给定的图,最小点覆盖等于最大匹配,最大独立集等于最小点覆盖,题目让求最大独立集,实际上就是最大匹配。

先用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;
}
View Code

 

L - L

 POJ - 2349 

对于一颗给定的最小生成树,当你选择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;
}
View Code
原文地址:https://www.cnblogs.com/littlerita/p/12748812.html