Codeforces Round #377 (Div. 2)(D.E.F)

D.有n天,m科考试,给出每一天可以过哪一科,以及每科需要多少天复习,求最少要多少天考完,或者不可能。(n,m<=1e5)


思路:
我们可以进行二分答案,那么可以把每一科最后在那一天考计算出来,我们贪心让最早先结束的先做,最后判断一下答案就可以了。


E.题意:
有n个计算机和m个电脑设配器(只能一对一使用,且电压相同),每次我们可以对电脑设配器的电压降低一半(向上取整)
输出最多有多少个计算机能够使用以及此时最少降低的次数
对于每个电脑设配器需要降低电压的次数,哪一个电脑匹配哪一个设配器


思路:
我们可以发现,如果刚开始能够直接匹配的适配器和电脑直接匹配的话,这样方案一定是最优的,所以,
我们可以将全部设配器一起处理,处理一次的时候进行匹配,处理两次的时候进行匹配。。。


F.题目:给一个n个点m条无向边的无重边自环的连通图,让你把所有的边定向,使得从每个点出发能够到达的点数中,最小的那个尽量大。


思路:首先双连通分量里面的点一定都是能相互走到的,所以我们可以对双连通缩点,
然后形成一棵树,接下来有两种方法,
一种是二分答案,我们根据叶子节点从小往上可以确定每条边的方向
另外一种是贪心,至少有一个树上的点不能指向其它点,我们选择包含数目最多的点

PS:双连通定向写了一个下午


#include<bits/stdc++.h>
using namespace std;
const int N=4e5+100;
typedef pair<int,int> PI;
struct Edge{
    int to,next,id;
}e[N*2];
int head[N],low[N],dfn[N],belong[N],instack[N],Count[N],S[N];
int tot,top,scc,cnt,Pre[N];
vector<int>MP[N];

void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}

void addedge(int from,int to,int id){
    e[tot]=(Edge){to,head[from],id};
    head[from]=tot++;
}

void Tarjan(int u,int fa){
    low[u]=dfn[u]=++cnt,Pre[u]=fa;
    S[++top]=u,instack[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].to;
        if(v==fa)   continue;
        if(!dfn[v]){
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        scc++;
        while(1){
            int v=S[top--];
            instack[v]=0;
            belong[v]=scc;
            MP[scc].push_back(v);
            Count[scc]++;
            if(v==u)
                break;
        }
    }
}
vector<PI>G[N];
int n,ans_x[N],ans_y[N],vis[N],tot1;

void dfs(int x,int fa){
    for(int j=0;j<MP[belong[x]].size();j++){
        int u=MP[belong[x]][j];
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i].first,id=G[u][i].second;
            if(v==fa)   continue;
            dfs(v,u);
            ans_x[id]=v,ans_y[id]=u;
        }
    }
}

void Dfs(int u,int pre,int Belong){
    vis[u]=++tot1;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].to,id=e[i].id;
        if(v==pre||belong[v]!=Belong)  continue;
        if(vis[v]!=0&&vis[v]<vis[u])   ans_x[id]=u,ans_y[id]=v;
        else if(Pre[v]==u)
            ans_x[id]=u,ans_y[id]=v,Dfs(v,u,Belong);
    }
}

int f[N];
int find(int x){return f[x]==x ? x: f[x]=find(f[x]);}

int main(){
    int m,u,v;
    scanf("%d%d",&n,&m);
    tot=cnt=top=scc=0;
    for(int i=1;i<=n;i++)   f[i]=i;
    memset(head,-1,sizeof(head));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(instack,0,sizeof(instack));
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        addedge(u,v,i),addedge(v,u,i);
    }
    for(int i=1;i<=n;i++)   if(!dfn[i])  Tarjan(1,-1);
    int ans=0,st=1;
    for(int i=1;i<=n;i++){
        if(Count[belong[i]]>ans)    ans=Count[belong[i]],st=i;
        for(int j=head[i];j!=-1;j=e[j].next){
            int v=e[j].to,id=e[j].id;
            int x=find(belong[i]),y=find(belong[v]);
            if(belong[i]!=belong[v]&&x!=y)
                G[i].push_back((PI){v,id}),G[v].push_back((PI){i,id}),f[x]=y;
        }
    }
    dfs(st,0),tot1=0;
    printf("%d\n",ans);
    for(int i=1;i<=scc;i++) Dfs(MP[i][MP[i].size()-1],0,i);
    for(int i=0;i<m;i++)    printf("%d %d\n",ans_x[i],ans_y[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值