2017Astar资格赛1002 度度熊的王国战略

啊啊全局最小割?

看了一天没看懂

考虑一个最小割,把原图分成两半(废话

左边取一个点为S,右边去一个点为T,跑出来的最小割一定是答案(废话

于是取1为S,随机T,1000组,保证不重复,随机数据随便过

但是有卡点,3000个点被分成了2999+1或2998+2

这两种情况都是可以预处理的

当2997+3时有三个点随机到一个就行,1000次,A掉的概率有,大概每个点70%

想想卡点不多(2999+1,2998+2为主),随机至上(笑),反正过了


#include <ctime>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;++j)
#define red(j,k,l) for (int j=k;j>=l;--j)
#define N 3005
#define M 100005*2
#define inf 1000000007
#define min(a,b) (((a)<(b))?(a):(b))

using namespace std;
int n,m,a[M],b[M],c[M],d[M],e[M],pos;
struct Dinic{
    
    int st[N],to[M],ne[M],mx[M],fl[M],deep[N],que[N],cur[N],S,T,cnt;
	
    void add(int k,int l,int poi){
        
        to[++cnt]=l;
        mx[cnt]=poi;
        ne[cnt]=st[k];
        st[k]=cnt;
        fl[cnt]=0;
        //if (poi>0) cout<<k<<' '<<l<<' '<<poi<<endl;
        
    }
    
    void set(){
    	
    	S=1,T=d[++pos];
        cnt=1;rep(i,1,n) st[i]=0;
        rep(i,1,m) add(a[i],b[i],c[i]),add(b[i],a[i],c[i]);
        
    }
    
    bool bfs(){
        int head=0,tail=1;
        que[1]=S;memset(deep,0,sizeof(deep));
        deep[S]=1;
        while (head!=tail){
            int x=que[++head];
            for (int i=st[x];i;i=ne[i])
                if (deep[to[i]]==0&&fl[i]!=mx[i]){
                    
                    deep[to[i]]=deep[x]+1;
                    que[++tail]=to[i];
                    if (to[i]==T) return 1;
                    
                }
            
        }
        return deep[T]>0;
        
    }
    
    int dfs(int k,int re){
        
        if (k==T||re==0) return re;
        int flow=0,f;
        for (int i=cur[k];i;cur[k]=i=ne[i])
            if (deep[to[i]]==deep[k]+1&&(f=dfs(to[i],min(re,mx[i]-fl[i])))>0){
                
				//printf("--!--%d %d\n",k,f);
                fl[i]+=f;fl[i^1]-=f;
                flow+=f;re-=f;
                if (!re) return flow;
                
            }
        if (re) deep[k]=-1;
        return flow;
        
    }
    
    int maxflow(){
        
        int flow=0;
        while (bfs()){
            
			//puts("ok");
            rep(i,1,n) cur[i]=st[i];  //зЂвт
            flow+=dfs(S,inf);
            
        }
		//printf("----%d\n",flow);
        return flow;
        
    }
    
} F;


int main(){
	
	srand(time(0));
	while (scanf("%d%d",&n,&m)!=EOF){
		
		for (int i=1;i<n;i++) d[i]=i+1;
		random_shuffle(d+1,d+n);
		pos=0;
		memset(e,0,sizeof(e));
		rep(i,1,m)
			scanf("%d%d%d",a+i,b+i,c+i),e[a[i]]+=c[i],e[b[i]]+=c[i];
		int ans=inf,pi;
		rep(i,1,n) ans=min(ans,e[i]);
		rep(i,1,m) ans=min(ans,e[a[i]]+e[b[i]]-2*c[i]);
		rep(i,1,min(500,n-1)) F.set(),pi=F.maxflow(),ans=min(ans,pi);
		printf("%d\n",ans);
		
	}
    
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值