去题面
QAQ光读题就恶心了我好久
一开始想的是把补丁和补丁建边,然后跑spfa,存当前的状态,看下一步是否能走。但是一看,状态最多有1000000+,补丁有最多100,vis数组和dis数组一定存不下。。。
QAQ那就把状态和状态之间建边吧,枚举每一种状态和每一个补丁,如果这个状态可以通过这个补丁变为另一个状态,建一条由该状态指向改变后状态的边,权值是该补丁的使用时间,跑最短路就行了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1000000+10;
int n,m,maxx,cnt,ans,inf;
int dis[maxn],fist[maxn],nxt[maxn<<2];
bool vis[maxn];
struct lxt
{
int v;
int bn,by,fn,fy;
}l[maxn];
struct hh
{
int f,t,v;
}e[maxn<<2];
queue<int>q;
void spfa()
{
dis[maxx]=0;
vis[maxx]=true;
q.push(maxx);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=fist[u];i!=-1;i=nxt[i])
{
int v=e[i].t;
if(dis[v]>dis[u]+e[i].v)
{
dis[v]=dis[u]+e[i].v;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
}
void build(int f,int t,int v)
{
e[++cnt]=(hh){f,t,v};
nxt[cnt]=fist[f];
fist[f]=cnt;
}
void done()
{
for(int j=0;j<=maxx;++j)
for(int i=1;i<=m;++i)
{
int exist=j;
if(((l[i].by&j)==l[i].by)&&(((~j)&l[i].bn)==l[i].bn))
{
exist=exist|l[i].fy;
exist=(~l[i].fn)∃
build(j,exist,l[i].v);
}
}
}
int main()
{
memset(fist,-1,sizeof(fist));
memset(dis,0x7f,sizeof(dis));
inf=dis[0];
scanf("%d%d",&n,&m);
maxx=(1<<n)-1;
for(int i=1;i<=m;++i)
{
scanf("%d",&l[i].v);
string s1,s2;
cin>>s1>>s2;
for(int j=0;j<n;++j)
{
if(s1[j]=='+') l[i].by=l[i].by|(1<<j);
else if(s1[j]=='-') l[i].bn=l[i].bn|(1<<j);
}
for(int j=0;j<n;++j)
{
if(s2[j]=='+') l[i].fy=l[i].fy|(1<<j);
else if(s2[j]=='-') l[i].fn=l[i].fn|(1<<j);
}
}
done();
spfa();
if(dis[0]!=inf) ans=dis[0];
printf("%d",ans);
return 0;
}