2018 BUPT Winter Training #8 Div.2

5 篇文章 0 订阅
3 篇文章 0 订阅

A - 无向图最小生成树

表白月加大佬,真是体贴萌新(笑)
最小生成树模板(话说是不是和之前树专题撞题了..)

#include <cstdio>
#include <vector>
#include <queue>
#include <utility>
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define PB push_back
#define MP make_pair
#define sec second
#define fir first
using namespace std;
typedef pair<int,int> pii;
vector<pii> E[1005];
bool vis[1005]={0};
priority_queue<pii,vector<pii>,greater<pii> >q;
pii tem;
int main(){
    int N,M,u,v,val;
    scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++){
        scanf("%d%d%d",&u,&v,&val);
        E[u].PB(MP(val,v));E[v].PB(MP(val,u));
    }
    int ans=0;
    q.push(MP(0,1));
    while(!q.empty()){
        tem=q.top();q.pop();
        if(vis[tem.sec])continue;
        vis[tem.sec]=1;
        ans+=tem.fir;
        TRV(i,E[tem.sec]){
            if(!vis[E[tem.sec][i].sec])q.push(E[tem.sec][i]);
        }
    }
    printf("%d",ans);
}

B - Arbitrage

单源最短路径判正反馈环。

#include <iostream>
#include <cstring> 
#include <string>
#include <map>
#include <vector>
#include <utility>
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define PB push_back
#define MP make_pair
#define sec second
#define fir first
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
using namespace std;
string name,na2;
map<string,int> currName;
struct edge{
    int u,v;
    double w;
    edge(){}
    edge(int _u,int _v,double _w){u=_u;v=_v;w=_w;}
};
vector<edge> E;
int Esize,n;
double dist[35];
bool bellman_ford(int start){
    bool released=0;
    memset(dist,0,sizeof(dist));
    dist[start]=1;
    FF(i,2,n){
        released=0;
        F(j,Esize){
            if(dist[E[j].v]<dist[E[j].u]*E[j].w){
                dist[E[j].v]=dist[E[j].u]*E[j].w;
                released=1;
            }
        }
        if(!released)return 0;
    }
    F(j,Esize)if(dist[E[j].v]<dist[E[j].u]*E[j].w)return 1;
    return 0;
}
int main(){
    int id1,id2,cas=1;
    double w;
    bool ZhuanDaRe;
    ios::sync_with_stdio(false);
    while(cin>>n){
        if(!n)break;
        E.clear();
        ZhuanDaRe=0;
        FF(i,1,n){cin>>name;currName[name]=i;}
        cin>>Esize;
        F(i,Esize){
            cin>>name>>w>>na2;
            E.PB(edge(currName[name],currName[na2],w));
        }
        FF(i,1,n)if(ZhuanDaRe|=bellman_ford(i))break;
        cout<<"Case "<<cas++<<": "<<(ZhuanDaRe?"Yes":"No")<<endl;
    }
}

C - Starry Night

(敲黑板)自创hash函数(可把我牛逼坏了?虽然前面还有几位大佬比我用的内存更少,太牛逼了!)这个hash函数的特点是可以使得直角旋转变换的相同图片拥有相同的hash值。

hash(G)=pG(pxpy(maxxpx)(maxypy)+hash_prime) h a s h ( G ) = ∑ p ∈ G ( p x p y ( m a x x − p x ) ( m a x y − p y ) + h a s h _ p r i m e )

#include <cstdio>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define PB push_back
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define MP make_pair
#define sec second
#define fir first
using namespace std;
typedef pair<int,int> pii;
int wayx[]={-1,-1,-1,0,0,1,1,1},wayy[]={-1,0,1,-1,1,-1,0,1};
char star[105][105];
int R,C,minx,miny,maxx,maxy,cluster=1;
vector<pii> E;
void dfsgetE(int y,int x){
    star[y][x]='0';
    E.PB(MP(y,x));
    if(minx>x)minx=x;
    if(miny>y)miny=y;
    if(maxx<x)maxx=x;
    if(maxy<y)maxy=y;
    int tx,ty;
    F(i,8){
        tx=wayx[i]+x;ty=wayy[i]+y;
        if(tx&&ty&&tx<=C&&ty<=R){
            if(star[ty][tx]=='1')dfsgetE(ty,tx);
        }
    }
}
map<unsigned int,int> hashmap;
void work(int y,int x){
    maxx=maxy=-1;minx=C+1,miny=R+1;
    E.clear();
    dfsgetE(y,x);
    minx--;miny--;
    maxx-=minx;maxy-=miny;
    maxx++;maxy++;
    unsigned int hash=0;
    TRV(i,E){
        y=E[i].fir-miny;x=E[i].sec-minx;
        hash+=233+(maxx-x)*(maxy-y)*x*y;
    }
    if(!hashmap[hash])hashmap[hash]=cluster++;
    x=hashmap[hash];
    TRV(i,E)star[E[i].fir][E[i].sec]=x-1+'a';
}
int main(){
    memset(star,0,sizeof(star));
    scanf("%d%d",&C,&R);
    FF(i,1,R)scanf("%s",star[i]+1);
    FF(i,1,R){         //y ,x
        FF(j,1,C)if(star[i][j]=='1')work(i,j);
    }
    FF(i,1,R)printf("%s\n",star[i]+1);
}

D - 迷宫游戏

最小生成树的扩展,cmp函数变化一下而已。

#include <cstdio>
#include <cstring>
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define MO 1061109567
using namespace std;
const int N = 505;
int t[N][N],w[N],dist[N],score[N]={0};
bool vis[N]={0};
int main(){
    int n,m,s,e,u,v;
    memset(t,0x3f,sizeof(t));
    memset(dist,0x3f,sizeof(dist));
    scanf("%d%d%d%d",&n,&m,&s,&e);
    F(i,n)scanf("%d",&w[i]);
    F(i,m){
        scanf("%d%d",&u,&v);
        scanf("%d",&t[u][v]);
        t[v][u]=t[u][v];
    }

    dist[s]=0;score[s]=w[s];
    int min,mini;
    F(i,n){
        min=MO;
        F(j,n)if(!vis[j]&&min>dist[j])min=dist[mini=j];
        vis[mini]=1;
        F(j,n){
            if(dist[mini]+t[mini][j]<dist[j]||dist[mini]+t[mini][j]==dist[j]&&score[mini]+w[j]>score[j]){
                dist[j]=dist[mini]+t[mini][j];
                score[j]=score[mini]+w[j];
            }
        }
    }
    printf("%d %d",dist[e>>>>>>
,score[e]);
}

E - 贫富差距

若图不连通,直接wrong,然后就是求最近距离了

#include <iostream>
#include <cstring>
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define MO 1061109567
using namespace std;
const int N = 50;
int dist[N+5][N+5],n;
const int DS_size=N;
int pre[DS_size+5];
int siz[DS_size+5];
inline void init(int n){
    for(int i=1;i<=n;i++)siz[pre[i]=i]=1;
}
inline int find(int x){
    return x==pre[x]?x:pre[x]=find(pre[x]);
}
inline int size(int x){
    return siz[find(x)];
}
void uni(int x,int y){
    dist[x][y]=1;
    if((x=find(x))!=(y=find(y))){
        if(siz[x]>siz[y])siz[pre[y]=x]+=siz[y];
        else siz[pre[x]=y]+=siz[x];
    }
}
int main(){
    int T,d,ans;char c;
    ios::sync_with_stdio(false);
    for(cin>>T;T--;){
        memset(dist,0x3f,sizeof(dist));
        cin>>n>>d;
        FF(i,1,n)dist[i][i]=0;
        init(n);
        FF(i,1,n)FF(j,1,n){
            cin>>c;
            if(c=='Y')uni(i,j);
        }
        if(size(1)<n){
            cout<<-1<<endl;
            continue;
        }
        FF(k,1,n)FF(i,1,n)FF(j,1,n){
            if(dist[i][j]>dist[i][k]+dist[k][j])  
                dist[i][j]=dist[i][k]+dist[k][j];
        }
        ans=0;
        FF(i,1,n)FF(j,1,n){
            if(dist[i][j]!=MO&&ans<dist[i][j])ans=dist[i][j];
        }
        cout<<ans*d<<endl;
    }
}

F - 畅通工程续

最小生成树模板题。

#include <iostream>
#include <cstring>
#include <vector>
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define PB push_back
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define MO 1061109567
using namespace std;
struct edge{
    int u,v,w;
    edge(){}
    edge(int _u,int _v,int _w){u=_u;v=_v;w=_w;}
};
vector<edge> E;
int n,m;
int dist[205];
bool bellman_ford(int start){
    bool released=0;
    memset(dist,0x3f,sizeof(dist));
    dist[start]=0;
    FF(i,2,n){
        released=0;
        F(j,m){
            if(dist[E[j].v]>dist[E[j].u]+E[j].w){
                dist[E[j].v]=dist[E[j].u]+E[j].w;
                released=1;
            }
        }
        if(!released)return 0;
    }
    //F(j,m)if(dist[E[j].v]<dist[E[j].u]*E[j].w)return 1;
    return 0;
}
int main(){
    int u,v,w;
    ios::sync_with_stdio(false);
    while(cin>>n>>m){
        E.clear();
        F(i,m){
            cin>>u>>v>>w;
            E.PB(edge(u,v,w));
            E.PB(edge(v,u,w));
        }
        m<<=1;
        cin>>u>>v;
        bellman_ford(u);
        cout<<(dist[v]==MO?-1:dist[v])<<endl;
    }
}

G - 2条不相交的路径

考虑到Query的规模到达1e5,要用tarjan算法离线判断双连通分量

#include <cstdio>
#include <cstring>
#include <vector>
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define PB push_back
using namespace std;

const int N=50000;
vector<int> E[N+5];
int dfsc,Tarjan_top,Cir;
int low[N+5],dfn[N+5];
int Tarjan_stack[N+5],preCir[N+5];
bool Tarjan_ins[N+5];
void init(int n){
    dfsc=1;
    Tarjan_top=Cir=0;
    memset(Tarjan_ins,0,sizeof(Tarjan_ins));
    memset(low,0,sizeof(low));
    memset(preCir,0,sizeof(preCir));
    memset(dfn,0,sizeof(dfn));
    FF(i,1,n)E[i].clear(); 
}
void Tarjan(int u,int last){
    int v;
    Tarjan_ins[Tarjan_stack[Tarjan_top++]=u]=1;
    low[u]=dfn[u]=dfsc++;
    TRV(i,E[u]){
        v=E[u][i];
        if(!dfn[v]){
            Tarjan(v,u);
            if(low[v]<low[u])low[u]=low[v];
        }else if(v!=last&&Tarjan_ins[v]&&dfn[v]<low[u])low[u]=dfn[v];
    }
    if(dfn[u]==low[u]){
        Cir++;
        do{
            preCir[v=Tarjan_stack[--Tarjan_top]]=Cir;
            Tarjan_ins[v]=0;
        }while(Tarjan_top>0&&v!=u);
    }
}
int main(){
    int m,n,u,v;
    init(n);
    scanf("%d%d",&m,&n);
    F(i,n){
        scanf("%d%d",&u,&v);
        E[u].PB(v);E[v].PB(u);
    }
    FF(i,1,n)if(!dfn[i])Tarjan(i,-1);
    int Q;
    scanf("%d",&Q);
    F(q,Q){
        scanf("%d%d",&u,&v);
        puts((preCir[u]==preCir[v])?"Yes":"No");
    }
}

H - 天气晴朗的魔法

求最小生成树最大边权下的最大生成树。

#include <cstdio>
#include <vector>
#include <algorithm>
#define INTMAX 0x7fffffff
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define all(x) x.begin(),x.end()
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define PB push_back
using namespace std;
struct edge{
    int u,v;
    int w;
    edge(){}
    edge(int _u,int _v,int _w){u=_u;v=_v;w=_w;}
};
const int N=100000;
vector<edge> E;
bool vis[N+5]={0};
bool cmp(edge x,edge y){
    return x.w>y.w;
}
const int DS_size=N;
int pre[DS_size+5];
int siz[DS_size+5];
inline void init(int n){
    for(int i=1;i<=n;i++)siz[pre[i]=i]=1;
}
inline int find(int x){
    return x==pre[x]?x:pre[x]=find(pre[x]);
}
inline int size(int x){
    return siz[find(x)];
}
bool uni(int x,int y){
    if((x=find(x))!=(y=find(y))){
        if(siz[x]>siz[y])siz[pre[y]=x]+=siz[y];
        else siz[pre[x]=y]+=siz[x];
        return 1;
    }
    return 0;
}
int main(){
    int N,M,u,v,val;
    scanf("%d%d",&N,&M);
    init(N);
    for(int i=0;i<M;i++){
        scanf("%d%d%d",&u,&v,&val);
        E.PB(edge(u,v,val));
    }
    sort(all(E),cmp);
    int maxw=-INTMAX;
    long long ans=0;
    TRV(i,E){
        if(uni(E[i].u,E[i].v)&&maxw<E[i].w)maxw=E[i].w;
    }
    init(N);
    F(i,M){
        if(E[i].w>maxw)continue;
        if(uni(E[i].u,E[i].v))ans+=E[i].w;
    }
    printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值