zoj3620 限定时间内从a点到b点的收益最大值(状压+搜索)

注意到了ed点后仍能把剩余时间用在继续访问其他点。所以不能标记某个点是否访问过(因为可能要折回),而是用【某种状态+出点】标记。

#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include<queue>
using namespace std;
struct node{
	int a,b,c;
	node(int aa=0,int bb=0,int cc=0){
		a=aa;b=bb;c=cc;
	}
	bool operator < (const node &x) const{
		if(a!=x.a)
			return a<x.a;
		else if(b!=x.b)
			return b<x.b;
		else if(c!=x.c)
			return c<x.c;
	}
};
int y[15];
int x[15][15];
int vis[2048][15];
int main(){
	int n,m,t;
	while(cin>>n>>m>>t){
		memset(x,0,sizeof(x));
		memset(vis,-1,sizeof(vis));
		int st,ed;
		cin>>st>>ed;
		for(int i=0;i<n;++i)
			cin>>y[i];
		int a,b,c;
		while(m--){
			cin>>a>>b>>c;
			x[a][b]=c;
			x[b][a]=c;
		}
		queue<node> q;
		q.push(node((1<<st),st,0)); //访问状态,起始点,时间(第二个参数的作用是保证一定形成欧拉通路) 
		vis[1<<st][st]=0;
		int maxx=0;
		while(!q.empty()){
			node fr=q.front();
			a=fr.a,b=fr.b,c=fr.c; 
			q.pop();
			int s=0;
			if(b==ed){
				for(int i=0;i<n;++i){
					if(a&(1<<i))
						s+=y[i];
				}
				maxx=max(maxx,s);
			}
			for(int i=0;i<n;++i){
				if(x[b][i]==0) continue;
				if(c+x[b][i]<=t&&vis[a|(1<<i)][i]==-1){ //要以vis标记,否则MLE 
					vis[a|(1<<i)][i]=c+x[b][i];
					q.push(node((a|(1<<i)),i,c+x[b][i]));
				}
				else if(c+x[b][i]<=t&&vis[a|(1<<i)][i]>c+x[b][i]){
					vis[a|(1<<i)][i]=c+x[b][i];
					q.push(node((a|(1<<i)),i,c+x[b][i]));
				}
			}
		}
		cout<<maxx<<endl;
	}
	return 0;
}
另一种dfs做法:

#include <stdio.h>
#include <string.h>
int dis[10][10], room[10];
int max, s, e, n, m, t;
char psd[10];

void DFS(int x, int time, int sum)
{
    int i;
    
    if(psd[x] == 0) sum += room[x];
    psd[x] ++;

    if(x == e)
        max = sum > max? sum : max;

    for(i = 0; i < n; i++)
        if(psd[x] < n && dis[x][i] && time >= dis[x][i]) DFS(i, time-dis[x][i], sum);

    psd[x] --;
}

int main(void)
{
    int i, a, b, c;
    
    while(scanf("%d%d%d", &n, &m, &t) != EOF)
    {
        memset(dis, 0, sizeof(dis));
        memset(psd, 0, sizeof(psd));
        
        scanf("%d%d", &s, &e);
        
        for(i = 0; i < n; i++)
            scanf("%d", &room[i]);

        for(i = 0; i < m; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            dis[a][b] = c;
            dis[b][a] = c;
        }
        
        max = 0;
        DFS(s, t, 0);
        printf("%d\n", max);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值