【ZOJ 2103】 Marco Popo the Traveler

题目来源

继续深搜题,不算难,但又碰到恶心的WA,debug若干个小时后才发现没有把非连通图的情况考虑进去,在调用dfs前要调用check函数(也是深搜)检查是否为连通图,如不是则直接打印 "No"。思维严密性还是有点欠缺


#include<iostream>
#include<fstream>
#include<cstring>
#include<vector>
#include<map>
//#include<map>
//#include "debug.h"
using namespace std;

int N,C,H;
bool visit[10][10];
int color[10][10];
//int h[10];
int res = 50;
int curColor = -1; //车轮当前颜色
int cur = -1;  //当前已更换颜色次数
int visited = 0;  //当前已走过的highway总数
map<int,vector<int> > tab;

int chk[10];  //用于检查是否为联通图

void check(int k,int &cnt){

	if(chk[k] == 2) return;  //已检查过该节点
	chk[k] = 1;  //正在检查中
	vector<int> &v = tab[k];

	for(int i=0;i<v.size();i++){
		if(chk[v[i]] == 0) check(v[i],cnt);
	}

	chk[k] = 2;  //检查完毕
	cnt++;
}

void dfs(int k){

	if(visited == H){ res = min(res,cur); return; } //一种可行方案

	vector<int> &v = tab[k];
	
	for(int i=0;i<v.size();i++){
		int lastColor = -2;
		if(!visit[k][v[i]]){
	
			visit[v[i]][k] = visit[k][v[i]] = true;
			if(color[k][v[i]]!=curColor){ 
				cur++;
				if(cur>=res){  //剪枝,
					visit[v[i]][k] = visit[k][v[i]] = false;
					cur--;
					break;  //跳出循环
				}
				else{ lastColor = curColor; curColor = color[k][v[i]]; }
			}
			visited++;  //决定访问(k,i)
			
			dfs(v[i]);

			if(lastColor!=-2){
				curColor = lastColor;  //lastColor!=-2说明此次改变过颜色,回溯到之前的颜色
				cur--;
			}

			visited--;
			visit[k][v[i]] = visit[v[i]][k] = false;  
		}
	}
}

int main(){
	//ifstream cin("input.txt");
	while(cin>>N>>C>>H && (N+C+H)!=0){
		//initialize

		for(int i=0;i<N;i++)
			for(int j=0;j<N;j++) color[i][j] = -3;
		
		curColor = -1;
		res = 50;
		cur = -1;
		visited = 0;
		tab.clear();
		memset(visit,0,100);
		memset(chk,0,10*sizeof(int));

		int a,b,c;
		for(int i=0;i<H;i++){
			cin>>a>>b>>c;
			color[a][b] = color[b][a] = c;
			if(tab.find(a) == tab.end()) tab[a] = vector<int>(); 
			tab[a].push_back(b);
			if(tab.find(b) == tab.end()) tab[b] = vector<int>();
			tab[b].push_back(a);

		}
		int odd = 0;
		for(int i=0;i<N;i++) if(tab[i].size()%2) ++odd;
		if(odd>2){ cout<<"No\n"; continue;}

		//检查是否为连通图
		int cnt = 0;
		check(0,cnt);
		if(cnt<N){ cout<<"No\n"; continue;}
		

		if(odd == 2){
			int k1=0,k2=0;
			while(tab[k1].size()%2==0) k1++;
			k2 = k1+1;
			while(tab[k2].size()%2==0) k2++;
			
			curColor = -1; dfs(k1);
			
			//initialize
			memset(visit,0,100);
			cur = -1;
		    visited = 0;
			curColor = -1;

			dfs(k2);	
		} 

		else{		
			for(int i=0;i<N;i++){ 		
			
				dfs(i);
				//initialize
				memset(visit,0,100);
				cur = -1;
				visited = 0;
				curColor = -1;	
			}
		}

		cout<<res<<endl;

		//initialize

	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值