【2018年全国多校算法寒假训练营练习比赛(第四场)】ABCDEFGH

A石油采集

分析:二分匹配。
一个油田只能够和一个油田匹配被瓢走 ,所以我们 对每一个油田 遍历其四周,如果也有油田,那么就建立边表示有可能匹配。 最后匈牙利算法求最大匹配就好了。

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 50*50+11;
const int M = 1E6+11;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const LL inff = 0x3f3f3f3f3f3f3f3f;

int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
    while(ch<='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
/*-------------------------*/
struct Edge {
    int from,to,next;
}edge[M];
int head[N],top;
void init(){
    memset(head,-1,sizeof(head));
    top=0;
}
void addedge(int a,int b){
    Edge e={a,b,head[a]};
    edge[top]=e; head[a]=top++;
}
int used[N],pipei[N];
bool Find(int x){
    for(int i=head[x];i!=-1;i=edge[i].next){
       Edge e=edge[i];
       if(!used[e.to]){
            used[e.to]=1;
            if(pipei[e.to]==-1 || Find(pipei[e.to])){
                pipei[e.to]=x;

                return true;
            }
       }
    }
    return false;
}
int  to[4][2]={0,1,0,-1,1,0,-1,0};
bool mp[N][N];
int  solve(int n){
    memset(pipei,-1,sizeof(pipei));
    int ans=0;
    for(int i=1;i<=n*n;i++){
        memset(used,0,sizeof(used));
        if(Find(i) ) ans++;
    }
    return ans;
}

int main(){
    int T;scanf("%d",&T);int zz=1;
    while(T--){
        init();
        memset(mp,0,sizeof(mp));
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++){
            string s;cin>>s;
            for(int j=0;j<n;j++){
                if(s[j]=='#') mp[i][j+1]=true;
                else mp[i][j+1]=false;
            }
        }


      /* for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                printf("%d",mp[i][j]);
            }
            puts("");
        }*/


        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(!mp[i][j]) continue;
                for(int k=0;k<4;k++){
                    int nx=i+to[k][0]; int ny=j+to[k][1];
                    if(mp[nx][ny])
                        addedge((i-1)*n+j,(nx-1)*n+ny);
                    //  mp[nx][ny]=false ;
                }
            }
        }
        printf("Case %d: %d\n",zz++,solve(n)/2); // 重复
    }
return 0;
}

/*

2
6
......
.##...
......
.#..#.
.#..##
......
4
###.
#...
.###
..#.

*/

B道路建设

分析:最小生成树模板题
代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 1e5 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL  inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);

int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
    return x*f;
}
/*----------------------------------*/
struct Edge{
    int from,to,val;
}edge[M];
bool cmp(Edge a,Edge b){
    return a.val<b.val;
}
int pre[N];

void init(int n){
    for(int i=0;i<=n;i++) pre[i]=i;
}
int Find(int x){
    return x==pre[x]?x:(pre[x]=Find(pre[x]));
}
void Join(int x,int y){
    x=Find(x);y=Find(y);
    if(x!=y) pre[x]=y;
}
int main(){
    int c,n,m;
    while(scanf("%d%d%d",&c,&n,&m)!=EOF){
        init(m);
         for(int i=0;i<n;i++)
            scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].val);
         sort(edge,edge+n,cmp);

         int ans=0; int flag=1;
         for(int i=0;i<n;i++){
            Edge e=edge[i];
            if(Find(e.to)!=Find(e.from)){
                Join(e.to,e.from);
                ans+=e.val;
            }
         }
        if(ans<=c) puts("Yes") ;
        else puts("No");
    }
return 0;
}

/*
链接:https://www.nowcoder.net/acm/contest/76/B
来源:牛客网

20 10 5
1 2 6
1 3 3
1 4 4
1 5 5
2 3 7
2 4 7
2 5 8
3 4 6
3 5 9
4 5 2


10 2 2
1 2 5
1 2 15
*/


C求交集

分析:二分查找。
我用map MLE了..QAQ

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 2e6 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL  inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);

int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
    return x*f;
}
/*----------------------------------*/
int a[N];
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        int have=0;
        for(int i=0;i<m;i++){
            int c;scanf("%d",&c);
            int pos=lower_bound(a,a+n,c)-a;
            if(a[pos]==c) {
                if(have++) putchar(' ');
                printf("%d",c);
            }
        }
        if(!have) puts("empty");
        else puts("");
    }
return 0;
}

D 小明的挖矿之旅

分析: 因为每个点只能够右和下移动,所以整个图就相当于一个DAG图。然后讨论入度为0 和出度为0的个数就行了

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 1000*1000 +11;
const int M = 1000+11;
const int inf = 0x3f3f3f3f;
const LL  inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);

int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
    return x*f;
}
/*----------------------------------*/

//vector<int>ve[N];
int in[N],out[N];
void init(int n){
    for(int i=0;i<n;i++) {
       // ve[i].clear();
        out[i]=in[i]=0;
    }
}
void addedge(int a,int b){
   // ve[a].push_back(b);
    in[b]++; out[a]++;
}
bool mp[M][M];
void show(int n,int m){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            printf("%d",mp[i][j]);
        }
        puts("");
    }
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        init(n*m);memset(mp,0,sizeof(mp));
        for(int i=0;i<n;i++){
            string s;cin>>s;
            for(int j=0;j<m;j++){
                if(s[j]=='.') mp[i+1][j+1]=true;
                else mp[i+1][j+1]=false;
            }
        }
       // show(n,m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]){
                    int nx=i+1;int ny=j;
                    if(mp[nx][ny]) addedge((i-1)*m+j-1,(nx-1)*m+ny-1);
                    nx=i;ny=j+1;
                    if(mp[nx][ny]) addedge((i-1)*m+j-1,(nx-1)*m+ny-1);
                }
            }
        }
        int a,b,c;
        a=b=c=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]){
                     if(in[(i-1)*m+j-1]==0) a++;
                     if(out[(i-1)*m+j-1]==0) b++;
                     c++;
                }
            }
        }
         if(c==0) puts("0");
         else if(a==c&&b==c) printf("%d\n",a-1);
         else printf("%d\n",max(a,b));
    }
return 0;
}

E 通知小弟

分析:scc+缩点 ,求缩点后的入度 ,如果入度为0且HA能够通知到的间谍 不在这个缩点里的话,肯定是-1 ,否则就是入度为0的点的个数。
只要入度为0的被通知了,那么入度不为的点肯定会由入度为0的传过来。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 1000 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL  inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);

int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
    return x*f;
}
/*----------------------------------*/
struct Edge{
    int from,to,nexts;
}edge[M];
int head[N],top;
int n,m;
void init(){
    memset(head,-1,sizeof(head)) ;
    top=0;
}
void addedge(int a,int b){
    Edge e={a,b,head[a]} ;
    edge[top]=e;head[a]=top++;
}
int dfn[N],low[N];
int sccno[N],scc_cnt;
stack<int>S; bool Instack[N];
vector<int>scc[N];
int mp[N][N];
int dfs_clock;
void tarjan(int now){
    low[now]=dfn[now]=++dfs_clock;
    S.push(now);Instack[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].nexts){
        Edge e=edge[i];
        if(!dfn[e.to]){
            tarjan(e.to);
            low[now]=min(low[now],low[e.to]);
        }else if(Instack[e.to])
            low[now]=min(low[now],dfn[e.to]);
    }
    if(dfn[now]==low[now]){
        scc_cnt++;scc[scc_cnt].clear();
        for(;;){
            int nexts=S.top();S.pop();Instack[nexts]=0;
            sccno[nexts]=scc_cnt;
            scc[scc_cnt].push_back(nexts);
            if(nexts==now) break;
        }
    }
}
void find_cut(int le,int ri){
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(Instack,0,sizeof(Instack));
    memset(sccno,0,sizeof(sccno));
    dfs_clock=scc_cnt=0;
    for(int i=le;i<=ri;i++)
        if(!dfn[i]) tarjan(i);
}
int in[N];
void suodian(){  // 建立DAG图
    for(int i=1;i<=scc_cnt;i++)
    memset(mp[i],0,sizeof(mp[i])); 
   for(int i=1;i<=scc_cnt;i++) in[i]=0;
    for(int i=0;i<top;i++){
        Edge e=edge[i];
        int now=sccno[e.from];
        int nexts=sccno[e.to];
        if(now!=nexts){
            in[nexts]++;
            mp[now][nexts]=1;
        }
    }
}
int HA[N];
map<int,int>zzx;
int main(){
    int mm;
    while(scanf("%d%d",&n,&mm)!=EOF){
        init(); zzx.clear();
        for(int i=1;i<=mm;i++) scanf("%d",&HA[i]);
        for(int i=1;i<=n;i++){
            int num=0; scanf("%d",&num);
            for(int j=1;j<=num;j++){
                int zz; scanf("%d",&zz);
                addedge(i,zz);
            }
        }
         find_cut(1,n);
         suodian();
         //cout<<scc_cnt<<endl;
         for(int i=1;i<=mm;i++) zzx[sccno[HA[i]]]=1;
         int flag=1; int ans=0;
         for(int i=1;i<=scc_cnt;i++){
            if(in[i]==0){
                if(zzx[i]==0) flag=0;  // HA通知到的间谍有没有这个在这里联通快中
                ans++;
            }
         }
         if(!flag) puts("-1");
         else printf("%d\n",ans);
    }
return 0;
}

F Call to your teacher

分析:floyd 求传递闭包 模板题
代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 100 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL  inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);

int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
    return x*f;
}
/*----------------------------------*/

int mp[N][N];
int n,m;
void wall(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=n;j++){
                mp[i][j]=mp[i][j]|(mp[i][k]&mp[k][j]);
            }
        }
    }
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(mp,0,sizeof(mp));
        while(m--){
            int a,b;scanf("%d%d",&a,&b);
            mp[a][b]=1;
        }
        wall();
        if(mp[1][n]) puts("Yes");
        else puts("No");
    }
return 0;
}


G 老子的意大利炮呢

分析: 状态压缩 + 优先队列的BFS
不难,但是太菜了,没时间写了。
三种物品,可以用状态压缩来表示当前拥有的状态 。
1<<1 表示拥有第一件物品,1<<2表示拥有第二件物品 ,1<<3表示拥有第三件物品.
然后 就是针对每种情况逐个分析就行了 ,这里一定要思路清晰,不然很容易错。
代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 100+11;
const int M = 1E6+11;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const LL inff = 0x3f3f3f3f3f3f3f3f;

int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
    while(ch<='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
/*-------------------------*/

struct Node {
    int x,y,step,state;
    bool operator<(const Node &b)const {
        return step>b.step;
    }
};
int mp[N][N],speed[1<<5];
int vis[N][N][1<<5]; 
int to[4][2]={1,0,0,1,-1,0,0,-1};
void Cal(int &cnt,int &tt,Node now){
    cnt=0; tt=1;
    for(int i=1;i<=3;i++){
        if((1<<i)&now.state){
            cnt++; tt+=speed[1<<i];
        }
    }
}
void bfs(Node st){
    memset(vis,0,sizeof(vis));
    priority_queue<Node>Q;
    Q.push(st); vis[st.x][st.y][st.state]=1;
    while(!Q.empty()){
        Node now=Q.top(); Q.pop();
        for(int i=0;i<4;i++){
            int nx=now.x+to[i][1]; int ny=now.y+to[i][0];
            if(mp[nx][ny]==0 || vis[nx][ny][now.state]) continue;  //对所有的情况逐个分析   关键 

            if(mp[nx][ny]==6){
                int cnt,tt; Cal(cnt,tt,now);
                if(cnt!=3){
                    Node next={nx,ny,now.step+tt,now.state};
                    vis[nx][ny][next.state]=1;
                    Q.push(next);
                }
                continue;
            }
            if(mp[nx][ny]==5){
                int cnt,tt;  Cal(cnt,tt,now);
                if(cnt==3) {
                    //printf("%d \n",tt);
                    printf("%d\n",now.step+tt);
                    return ;
                }

                continue;
            }
            if(mp[nx][ny]==1) {
               int cnt,tt; Cal(cnt,tt,now);
                Node ne={nx,ny,now.step+tt,now.state};
                vis[nx][ny][ne.state]=1; Q.push(ne);
                continue;
            }
            if(mp[nx][ny]>=2&&mp[nx][ny]<=4){
               int cnt,tt;  Cal(cnt,tt,now);

                Node ne={nx,ny,now.step+tt,now.state | (1<<(mp[nx][ny]-1))};
                vis[nx][ny][ne.state]=1; Q.push(ne);

                Node next={nx,ny,now.step+tt,now.state};
                vis[nx][ny][next.state]=1;  Q.push(next);
                continue;
            }
        }
    }
    puts("-1");
}

void show(int n,int m){ //debug 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++) {
            printf("%d",mp[i][j]);
        }
        puts("");
    }
}

int main(){
    memset(mp,0,sizeof(mp));
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        string s;cin>>s;
        for(int j=0;j<m;j++){
            if(s[j]=='#') mp[i][j+1]=6;
            else mp[i][j+1]=1;
        }
    }

    Node st;
    for(int i=1;i<=5;i++){
        int x,y;scanf("%d%d",&x,&y);
        if(i==1) { st.x=x;st.y=y;st.step=0;st.state=0; }
        mp[x][y]=i;
    }
   // show(n,m);
    speed[0]=1;
    for(int i=1;i<=3;i++){
        int t;scanf("%d",&t);
        speed[1<<i]=t;
    }
   // for(int i=1;i<=3;i++) printf("%d ",speed[1<<i]);

    bfs(st);
return 0;
}

/*

3 5
##.##
.#.#.
##.##
1 3 2 1 2 3 2 5 3 3
1 5 4

*/

H 老子的全排列呢

分析:直接调用函数 。
代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long

const int N = 500 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL  inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);

int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
    return x*f;
}
/*----------------------------------*/

int a[8]={1,2,3,4,5,6,7,8};
int main(){
    do{
        for(int i=0;i<8;i++) printf("%d%s",a[i],i==7?"":" ");
        puts("");
    }while(next_permutation(a,a+8));
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值