uva 658 UVA 658 It's not a Bug, it's a Feature!

本文介绍了一种使用二进制状态压缩的最短路径快速算法(SPFA)解决特定图论问题的方法。文章重点讲解了如何利用位运算进行高效的状态转移,并通过实例代码展示了算法的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本题有两大难点,一是建图。其实无论邻接表还是邻接矩阵貌似建完整图的时间复杂度都比较大,而且好多状态未必用的到,因而不如干脆不建完整图,每次都扫描一遍转换规则,如果可以生成另一个状态就将另一个状态直接入队即可。状态可以用二进制表示。

二是判断当前状态,用二进制来判断。

  ①判定某些位置是否为1,如判定2、4位置为1,则转化为判断x|0101是否等于x。

    ②判定某些位置是否为0,如判定2、4位置为0,则转化为判断x&1010是否等于x。

    ③将某些位置转化为1,如2、4位置转化为1,则令x=x|0101。

    ④将某些位置转化为0,如2、4位置转化为0,则令x=x&1010。

//  Created by Chenhongwei in 2015.
//  Copyright (c) 2015 Chenhongwei. All rights reserved.

#include "iostream"
#include "cstdio"
#include "cstdlib"
#include "cstring"
#include "climits"
#include "queue"
#include "cmath"
#include "map"
#include "set"
#include "stack"
#include "vector"
#include "sstream"
#include "algorithm"
using namespace std;
const int inf=1e9;
const int maxn=(2<<20)+100;
typedef long long ll;
bool vis[maxn];
int d[maxn];
int  b[2][150],a[2][150];
int n,m;
int w[150];
void SPFA()
{
	memset(vis,0,sizeof vis);
	memset(d,0x3f,sizeof d);
	int inti=(1<<n)-1;
	queue<int >q;
	q.push(inti);
	d[inti]=0;
	vis[inti]=1;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		// cout<<u<<endl;
		vis[u]=0;
		for(int i=1;i<=m;i++)
			if((u&b[1][i])==u&&(u|b[0][i])==u)
			{
				int v=u;
				v|=a[0][i];
				v&=a[1][i];
				if(d[v]>d[u]+w[i])
				{
					d[v]=d[u]+w[i];
					if(!vis[v])
					{
						vis[v]=1;
						q.push(v);
					}
				}
			}
	}
	if(d[0]>inf)
		cout<<"Bugs cannot be fixed."<<endl<<endl;
	else 
		cout<<"Fastest sequence takes "<<d[0]<<" seconds."<<endl<<endl;
}
int main()
{	
	//ios::sync_with_stdio(false);
	// freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int kase=0;
	while(scanf("%d%d",&n,&m)&&(n+m))
	{
		printf("Product %d\n",++kase);
		char s[150],t[150];
		memset(a,0,sizeof a);
		memset(b,0,sizeof b);
		for(int i=1;i<=m;i++)
		{
			scanf("%d%s%s",&w[i],s,t);
			for(int j=0;j<n;j++)
			{
				if(s[j]=='+')
					b[0][i]+=(1<<j);
				if(s[j]!='-')
					b[1][i]+=(1<<j);
				if(t[j]=='+')
					a[0][i]+=(1<<j);
				if(t[j]!='-')
					a[1][i]+=(1<<j);
			}
			// cout<<b[0][i]<<' '<<b[1][i]<<' '<<a[0][i]<<' '<<a[1][i]<<endl;
		}
		SPFA();
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值