题意:
1. 直接给你一张图:由W,I,N三个字母构成;
2. 当WIN三个字母成一条直线或成“L”型时,为一种满足的情况;
3. 一个字母只能在一个可满足的情况中,求情况的最大数
思路:
网络流裸题:
初步想法:
1。W向I连一条边,I向N连一条边;
2。设置超级源点S向每个W连边,每个N向超级汇点T连边,跑一遍最大流;
3。问题所在:
W
W I N
N
这种情况得出的答案应该是1,但是跑出来的结果却不是,显然有问题。
4。解决方法:
拆点:
将 I 点拆成点 I1 和点 I2,两个点的流量设为1,这样跑一边最大流就行了
题目链接:
题目链接
AC代码:
(吐槽一句:这个题的输入输出真恶心)
#include
#include
using namespace std;
typedef long long LL;
const int MX=5005;
const LL inf=1e17;
LL ans;
int fr[MX],h[MX],nh[MX];
int s,t,e,n,m;
char ss[MX][MX];
int dir[4][2]={1,0,-1,0,0,1,0,-1};
struct lp
{
int t,ne;
LL w;
}a[MX*100];
void ins(int f,int t,LL w)
{
a[++e].t=t,a[e].ne=fr[f],fr[f]=e,a[e].w=w;
a[++e].t=f,a[e].ne=fr[t],fr[t]=e,a[e].w=0;
}
LL Min(LL x,LL y)
{
return xint u,LL fl)
{
if (u==t) return fl;
LL res=fl;
for (int i=fr[u];i;i=a[i].ne){
if (a[i].w&&h[a[i].t]+1==h[u]){
LL t=sap(a[i].t,Min(res,a[i].w));
a[i].w-=t,a[i^1].w+=t;
if (!(res-=t)) return fl;
}
}
if (!(--nh[h[u]])) h[t]=t;
++nh[++h[u]];
return fl-res;
}
int main()
{
while(1){
int flag=1;
n=0;
while(gets(ss[n])){
n++;
if(!ss[n-1][0]){
n--;flag=0;
break;
}
}
m=strlen(ss[0]);
//printf("*%d %d\n",n,m );
memset(fr,0,sizeof(fr));
memset(nh,0,sizeof(nh));
memset(h,0,sizeof(h));
s=1;t=2+n*m*2;ans=0;e=1;
for(int i=0;ifor(int j=0;jif(ss[i][j]=='I'){
ins(i*m+j+1+1,i*m+j+1+n*m+1,1LL);
for(int h=0;h<4;++h){
int px=i+dir[h][0],py=j+dir[h][1];
if(px<0||py<0||px>=n||py>=m)continue;
if(ss[px][py]=='W')ins(1+px*m+py+1,1+i*m+j+1,1LL);
if(ss[px][py]=='N')ins(n*m+1+i*m+j+1,1+px*m+py+1,1LL);
}
}
if(ss[i][j]=='W')ins(1,i*m+j+1+1,1LL);
if(ss[i][j]=='N')ins(i*m+j+1+1,t,1LL);
}
}
nh[0]=t;
while (h[t]!=t){
ans+=sap(s,inf);
}
printf("%lld\n",ans);
if(flag)break;
}
return 0;
}
其他题处理
#include
#include
#include
#include
#include
#include
#define mm1(a) memset((a),-1,sizeof((a)))
#define mm0(a) memset((a),0,sizeof((a)))
#define mmx(a) memset((a),0x3f,sizeof((a)))
using namespace std;
typedef long long LL;
const int N = 100005;
const int INF = 0x3f3f3f3f;
int n,m,tot,vt,vs;
int d[N],head[N];
std::vector<int> v[N];
set<int>have;
int numm[N];
char tools[10000];
struct lp{
int to,w,nex;
lp(){}
lp(int a,int b,int c){to=a;w=b;nex=c;}
}cw[N<<2];
int pigNum[N],pigTo[N];
inline void add(int a,int b,int c){
cw[++tot]=lp(b,c,head[a]);
head[a]=tot;
cw[++tot]=lp(a,0,head[b]);
head[b]=tot;
}
bool bfs(){
mm1(d);
queue<int>Q;
Q.push(vt);d[vt]=0;
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(int i=head[u];i!=-1;i=cw[i].nex){
int v=cw[i].to;
if(cw[i^1].w&&d[v]==-1){
d[v]=d[u]+1;
Q.push(v);
}
}
}
return d[vs]!=-1;
}
int dfs(int x,int f){
if(x==vt||f==0) return f;
int use=0,w;
for(int i=head[x];i!=-1;i=cw[i].nex){
int to=cw[i].to;
if(d[to]==d[x]-1 && cw[i].w){
w=dfs(to,min(cw[i].w,f-use));
cw[i].w-=w,cw[i^1].w+=w;
use+=w;
if(use==f) return f;
}
}
return use;
}
inline void init(){
tot=-1;
mm1(head);
vs=0,vt=n+m+1;
}
/*
1:Dinic最后一次的bfs
2:通过删除仪器与T的边判断仪器,再判断实验
3:如果原向边和残留都是0则不要。若正向边或反向边大于0则要
*/
int main(){
scanf("%d%d",&m,&n);
init();
int sum=0;
for(int i=1; i<=m; i++) {
memset(tools,0,sizeof(tools));
int ulen=0,tool;
scanf("%d",&tool);
numm[i]=tool;
sum+=tool;
add(vs,i,tool);
cin.getline(tools,10000);
while(sscanf(tools+ulen,"%d",&tool)==1){
add(i,tool+m,INF);
v[i].push_back(tool);
if(tool==0)ulen++;
else {
while(tool){
tool/=10;
ulen++;
}
}
ulen++;
}
}
for(int i=1,x;i<=n;++i){
scanf("%d",&x);
add(i+m,vt,x);
}
int have_num=0,tmpans=0;
while(bfs())tmpans+=dfs(vs,INF);
for(int i=1;i<=m;++i){
if(d[i]==-1)printf("%d ",i);
}
printf("\n");
for(int i=1;i<=n;++i){
if(d[i+m]==-1)printf("%d ",i );
}
printf("\n");
printf("%d\n",sum-tmpans);
return 0;
}