【刷題】BZOJ 1458 士兵占領
阿新 • • 發佈:2018-08-04
template signed 所有 -- unsigned char 一個 turn 行數
有解的話輸出費用
Description
有一個M * N的棋盤,有的格子是障礙。現在你要選擇一些格子來放置一些士兵,一個格子裏最多可以放置一個士兵,障礙格裏不能放置士兵。我們稱這些士兵占領了整個棋盤當滿足第i行至少放置了Li個士兵, 第j列至少放置了Cj個士兵。現在你的任務是要求使用最少個數的士兵來占領整個棋盤。
Input
第一行兩個數M, N, K分別表示棋盤的行數,列數以及障礙的個數。 第二行有M個數表示Li。 第三行有N個數表示Ci。 接下來有K行,每行兩個數X, Y表示(X, Y)這個格子是障礙。
Output
輸出一個數表示最少需要使用的士兵個數。如果無論放置多少個士兵都沒有辦法占領整個棋盤,輸出”JIONG!” (不含引號)
Sample Input
4 4 4
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3
Sample Output
4
數據範圍
M, N <= 100, 0 <= K <= M * N
Solution
這題是自己想了個麻煩一點,慢了一點的算法,但是思路特簡單
一行一列只能有一個,套路,行列連邊
超級源點向所有行連邊,流量為行上需要布滿的士兵,費用為 \(0\)
所有列向超級匯點連邊,流量為列上需要布滿的士兵,費用為 \(0\)
如果某個位置沒有障礙,那麽將它的行列連邊,流量為 \(1\) ,費用為 \(1\)
跑費用流
然後判斷源點連出的和流向匯點的邊是否滿流,滿了就是滿足行列限制了,否則無解
#include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double #define ld long double #define ull unsigned long long const int MAXN=200+10,MAXM=MAXN*MAXN+10,inf=0x3f3f3f3f; int n,m,k,e=1,clk,s,t,answas,beg[MAXN],cur[MAXN],level[MAXN],p[MAXN],vis[MAXN],G[MAXN][MAXN],to[MAXM<<1],nex[MAXM<<1],cap[MAXM<<1],was[MAXM<<1],out[MAXM<<1]; std::queue<int> q; template<typename T> inline void read(T &x) { T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char ch='\0') { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(ch!='\0')putchar(ch); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} inline void insert(int x,int y,int z,int w) { to[++e]=y; nex[e]=beg[x]; out[e]=x; beg[x]=e; cap[e]=z; was[e]=w; to[++e]=x; nex[e]=beg[y]; out[e]=y; beg[y]=e; cap[e]=0; was[e]=-w; } inline bool bfs() { memset(level,inf,sizeof(level)); level[s]=0; p[s]=1; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); p[x]=0; for(register int i=beg[x];i;i=nex[i]) if(cap[i]&&level[to[i]]>level[x]+was[i]) { level[to[i]]=level[x]+was[i]; if(!p[to[i]])p[to[i]]=1,q.push(to[i]); } } return level[t]!=inf; } inline int dfs(int x,int maxflow) { if(x==t||!maxflow)return maxflow; vis[x]=clk; int res=0; for(register int &i=cur[x];i;i=nex[i]) if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+was[i]) { int f=dfs(to[i],min(maxflow,cap[i])); res+=f; cap[i]-=f; cap[i^1]+=f; answas+=f*was[i]; maxflow-=f; if(!maxflow)break; } return res; } inline void MCMF() { while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),dfs(s,inf); } int main() { read(n);read(m);read(k); s=n+m+1,t=s+1; for(register int i=1,x;i<=n;++i)read(x),insert(s,i,x,0); for(register int i=1,x;i<=m;++i)read(x),insert(i+n,t,x,0); while(k--) { int x,y;read(x);read(y); G[x][y]=1; } for(register int i=1;i<=n;++i) for(register int j=1;j<=m;++j) if(!G[i][j])insert(i,j+n,1,1); MCMF(); for(register int i=2;i<=e;i+=2) if((out[i]==s||to[i]==t)&&cap[i]) { puts("JIONG"); return 0; } write(answas,'\n'); return 0; }
【刷題】BZOJ 1458 士兵占領