T1:
还是翻译一下...(CtrlC+CtrlV)...
Seal
【题目背景】 NOI2030 前夜,作为出题人的 Z 君正在颓隔膜。这个隔膜是这样的:在上古 秘境中,勇者们发现了封印古代恶魔的地方。不幸的是,这里的封印已经濒临崩 溃,恶魔们即将苏醒。勇者们决定使用魔法水晶加固封印,让恶魔们再次沉睡。
【题目描述】 封印恶魔的地方可以看作是一个 n*m 的矩形,包含了 n*m 个祭坛,并且其 中有一些祭坛已经损坏了。如果 i+j 为偶数,那么第 i 行第 j 列的祭坛只要没有损 坏,就一定会封印有一个恶魔。 其他的没有损坏的祭坛可以用来放置魔法水晶,但是一个祭坛上只能放置一 个魔法水晶,并且一个魔法水晶只能向一个与它相邻的祭坛输送魔力,从而加固 封印。 对于一个恶魔来说,如果与它相邻的两个成直角的水晶同时向它所在的祭坛 输送魔力的话,它就会被再次封印。 现在 Z 君想知道他最多可以封印多少恶魔?
【输入格式】 第一行两个整数 n,m,含义见题目描述。 接下来 n 行,每行一个长度为 m 的字符串,只包含’X’和’.’。如果第 i 行第 j 个字符为’X’,则意味着第 i 行第 j 列的祭坛已经损坏。
【输出格式】 一行一个整数表示答案。
【样例输入】
3 3
…
…
…
【样例输出】
2
【数据规模与约定】
对于 40%的数据,m≤10。
对于 100%的数据,1≤n,m≤50,0≤K≤n*m。
分析:
考试的时候我的想法是这样滴:
因为每个恶魔四周都有四个点可以向它连边,而我们要求的是选择上下中的一个和左右中的一个向他连边...所以我们需要把这四个点分类...
因为发现左右的点和上下的点行编号的奇偶性永远不同,所以我们把水晶点按照行编号分为两类,S向奇数行编号的点连容量为1的边,奇数行编号的点向偶数行编号的点连容量为1,然后偶数行编号的点向恶魔连容量为1的边...我觉得可对了...但是我造了了一个3*3的数据卡了自己...
3 3
X..
.XX
XXX
ans=0,但是我跑出来是1TAT...
为什么不用我说了吧...
怎么解决...我思考了好久...还是不会...然后听完正解发现我就是个智障...
我们只需要把奇数行编号的点向恶魔连边然后恶魔向偶数行编号的点连边就好了...
这就是一种解决限制的方法...受教受教...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 //gao shan yang zhi,jing hang xing zhi 9 10 const int N=50+5,maxn=10000+5,maxm=2000000+5; 11 12 int n,m,S,T,cnt,hd[maxn],fl[maxm],to[maxm],nxt[maxm],pos[maxn]; 13 14 int mv[4][2]={0,1,0,-1,1,0,-1,0}; 15 16 char mp[N][N]; 17 18 inline bool bfs(void){ 19 memset(pos,-1,sizeof(pos)); 20 int head=0,tail=0,q[maxn]; 21 q[0]=S,pos[S]=0; 22 while(head<=tail){ 23 int top=q[head++]; 24 for(int i=hd[top];i!=-1;i=nxt[i]) 25 if(pos[to[i]]==-1&&fl[i]) 26 pos[to[i]]=pos[top]+1,q[++tail]=to[i]; 27 } 28 return pos[T]!=-1; 29 } 30 31 inline int find(int v,int f){ 32 if(v==T) 33 return f; 34 int res=0,t; 35 for(int i=hd[v];i!=-1&&f>res;i=nxt[i]) 36 if(pos[to[i]]==pos[v]+1&&fl[i]) 37 t=find(to[i],min(f-res,fl[i])),res+=t,fl[i]-=t,fl[i^1]+=t; 38 if(!res) 39 pos[v]=-1; 40 return res; 41 } 42 43 inline int dinic(void){ 44 int res=0,t; 45 while(bfs()) 46 while(t=find(S,inf)) 47 res+=t; 48 return res; 49 } 50 51 inline void add(int s,int x,int y){ 52 fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++; 53 fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++; 54 } 55 56 signed main(void){ 57 freopen("Seal.in","r",stdin); 58 freopen("Seal.out","w",stdout); 59 scanf("%d%d",&n,&m); 60 S=0,T=n*m*2+1;cnt=0; 61 memset(hd,-1,sizeof(hd)); 62 for(int i=1;i<=n;i++) 63 scanf("%s",mp[i]+1); 64 for(int i=1;i<=n;i++) 65 for(int j=1;j<=m;j++){ 66 if((((i+j)&1)==0)&&mp[i][j]!='X'){ 67 add(1,(i-1)*m+j,(i-1)*m+j+n*m); 68 for(int t=0;t<4;t++){ 69 int x=i+mv[t][0],y=j+mv[t][1]; 70 if(x>=1&&x<=n&&y>=1&&y<=m&&mp[i][j]!='X'){ 71 if(x&1) 72 add(1,(x-1)*m+y,(i-1)*m+j); 73 else 74 add(1,(i-1)*m+j+n*m,(x-1)*m+y); 75 } 76 } 77 } 78 else if(((i+j)&1)&&mp[i][j]!='X'){ 79 if(i&1) 80 add(1,S,(i-1)*m+j); 81 else 82 add(1,(i-1)*m+j,T); 83 } 84 } 85 printf("%d\n",dinic()); 86 return 0; 87 }//Cap ou pas cap. Cap.