zoukankan      html  css  js  c++  java
  • 【bzoj1565】 NOI2009—植物大战僵尸

    http://www.lydsy.com/JudgeOnline/problem.php?id=1565 (题目链接)

    题意

      给出$n*m$的棋盘,僵尸攻击每个格子可以获得$v$的分数,每个格子又会保护一些别的格子,想攻击被保护的格子必须先攻击没被保护的格子。问获得的最大分数。

    Solution

      建图,被保护的点向保护它的点连边。显然,环上的点是不可能被击败的,我们Tarjan以后把环上的点以及指向环的点扔掉。剩下的点做最大权闭合子图就好了。

      这里扔掉不是真的扔掉,只要不让S和T与之相连就好了。

    细节

      数组大小

    代码

    // bzoj1565
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf (1ll<<30)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=100010,maxm=1000010;
    int head[maxn],d[maxn],n,m,cnt,ans,tot,S,T;
    int size[maxn],dfn[maxn],low[maxn],bel[maxn],vis[maxn],val[maxn],st[maxn],DFN,scc,top;
    struct edge {int to,next,w;}e[maxm];
    pair<int,int> E[maxm];
    
    namespace Dinic {
    	void link(int u,int v,int w) {
    		e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
    		e[++cnt]=(edge){u,head[v],0};head[v]=cnt;
    	}
    	bool bfs() {
    		for (int i=S;i<=T;i++) d[i]=-1;
    		queue<int> q;q.push(S);d[S]=0;
    		while (!q.empty()) {
    			int x=q.front();q.pop();
    			for (int i=head[x];i;i=e[i].next)
    				if (e[i].w && d[e[i].to]<0) d[e[i].to]=d[x]+1,q.push(e[i].to);
    		}
    		return d[T]>0;
    	}
    	int dfs(int x,int f) {
    		if (x==T || f==0) return f;
    		int w,used=0;
    		for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]==d[x]+1) {
    				w=dfs(e[i].to,min(e[i].w,f-used));
    				used+=w,e[i].w-=w;e[i^1].w+=w;
    				if (used==f) return used;
    			}
    		if (!used) d[x]=-1;
    		return used;
    	}
    	int main() {
    		int flow=0;
    		while (bfs()) flow+=dfs(S,inf);
    		return flow;
    	}
    }
    
    void link(int u,int v) {e[++cnt]=(edge){v,head[u]};head[u]=cnt;}
    void Tarjan(int x) {
    	st[++top]=x;dfn[x]=low[x]=++DFN;
    	for (int i=head[x];i;i=e[i].next) {
    		if (!dfn[e[i].to]) {
    			Tarjan(e[i].to);
    			low[x]=min(low[x],low[e[i].to]);
    		}
    		else if (!bel[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
    	}
    	if (dfn[x]==low[x]) {
    		scc++;
    		for (;st[top]!=x;top--) bel[st[top]]=scc,size[scc]++;
    		bel[st[top--]]=scc;size[scc]++;
    	}
    }
    bool dfs(int x) {
    	if (vis[x]) return size[x];
    	if (size[x]>1) size[x]=0;
    	vis[x]=1;
    	for (int i=head[x];i;i=e[i].next) if (e[i].w) size[x]&=dfs(e[i].to);
    	return size[x];
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for (int i=0;i<n;i++)
    		for (int x,y,t,j=1;j<=m;j++) {
    			scanf("%d%d",&val[i*m+j],&t);
    			for (int k=1;k<=t;k++) scanf("%d%d",&x,&y),link(x*m+y+1,i*m+j);
    			if (j<m) link(i*m+j,i*m+j+1);
    		}
    	for (int i=1;i<=n*m;i++) if (!dfn[i]) Tarjan(i);
    	for (int i=1;i<=n*m;i++)
    		for (int j=head[i];j;j=e[j].next)
    			if (bel[i]!=bel[e[j].to]) E[++tot]=pair<int,int>(bel[i],bel[e[j].to]);
    	memset(head,0,sizeof(head));cnt=1;
    	for (int i=1;i<=tot;i++) Dinic::link(E[i].first,E[i].second,inf);
    	for (int i=1;i<=scc;i++) if (!vis[i]) dfs(i);
    	S=0,T=n*m+1;
    	for (int i=1;i<=n*m;i++) if (size[bel[i]]) {
    			if (val[i]>=0) Dinic::link(S,bel[i],val[i]),ans+=val[i];
    			else Dinic::link(bel[i],T,-val[i]);
    		}
    	ans=max(0,ans-Dinic::main());
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    《这个杀手不太冷》
    vim 程序编辑器
    wireshark 过滤规则
    使用c函数库的两个函数strtok, strncpy遇到的问题记录
    memset 导致的段错误(segmentation fault)
    LNMP 环境搭建
    cgic 中文文档
    virtualBox 不能开启一个新任务的错误
    PPTP&L2TP&PPPOE client and server configure
    netperf安装及使用
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6621976.html
Copyright © 2011-2022 走看看