题目链接:戳我
感觉虽然在所谓的网络流24题编制里,但是并没有看出来怎么用网络流做?(听说网络流24题全名不叫网络流24题???)
看到n的范围挺小的,我们考虑状压。
转移的过程可以放到图论里面,因为要求费用最小,所以我们想到了最短路!(笑
所以就是dij+状压转移嘛qwqwq(我就是不写spfa!!!)
注意一下非法情况的判断为f1里面包含,但是当前情况u不包含。或者f2里面不包含当前情况却包含了。
转移的下一个状态v对于f1的修改情况,我们这里采用减法操作,但是一定要判断这一位上是否有1再减去!(有可能本来就没有这个漏洞,所以就不需要修补啊qwq)
开始的情况为dis[(1<<n)-1],结束的情况为dis[0]。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
int n,m,t,T;
char cur1[21],cur2[21];
struct Node
{
int u,d;
friend bool operator <(struct Node x,struct Node y){return x.d>y.d;}
};
int head[1050000],dis[1050000],done[1050000],b1[110][21],b2[110][21],f1[110][21],f2[110][21],cost[110];
inline bool check(int now,int x)
{
for(int i=0;i<n;i++)
{
if(b1[x][i]==1&&!(now&(1<<i))) return false;
if(b2[x][i]==1&&(now&(1<<i))) return false;
}
return true;
}
inline void dij()
{
priority_queue<Node>q;
memset(dis,0x3f,sizeof(dis));
q.push((Node){T,0}),dis[T]=0;
while(!q.empty())
{
int u=q.top().u; q.pop();
if(done[u]) continue;
done[u]=1;
for(int i=1;i<=m;i++)
{
if(check(u,i)==false) continue;
int v=u;
for(int j=0;j<n;j++)
{
if(f1[i][j]) v-=v&(1<<j);
if(f2[i][j]) v|=1<<j;
}
if(dis[v]>dis[u]+cost[i])
dis[v]=dis[u]+cost[i],q.push((Node){v,dis[v]});
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
T=(1<<n)-1;
for(int i=1;i<=m;i++)
{
scanf("%d%s%s",&cost[i],cur1,cur2);
int len1=strlen(cur1),len2=strlen(cur2);
for(int j=0;j<len1;j++)
{
if(cur1[j]=='+') b1[i][j]=1;
if(cur1[j]=='-') b2[i][j]=1;
}
for(int j=0;j<len2;j++)
{
if(cur2[j]=='-') f1[i][j]=1;
if(cur2[j]=='+') f2[i][j]=1;
}
}
dij();
printf("%d\n",dis[0]==0x3f3f3f3f?0:dis[0]);
}