ZOJ 2103 Marco Popo the Traveler(搜索水题)

Marco Popo the Traveler


Time Limit: 2 Seconds      Memory Limit: 65536 KB


Marco Popo, the famous traveler, is traveling around the country of ACM. There are colored high-ways between cities (of course there is at most one high-way between any two cities), and his goal is to drive along each high-way once and only once. There is a strange rule to be followed when driving along: the color of one's tyres must match that of the high-way. As a result, he has to change tyres all the way he travels.

Given the total number of cities and the high-way map, you should decide at least how many times Popo needs to change tyres. Notice that Popo only changes tyres in cities, and he is allowed to start and end with tyres of arbitrary color.


Input

There are several test cases. Each test case begins with a line containing the total number of cities N (0 < N <= 10), the total number of colors C (0 < C <= 6), and the total number of high-ways in the country H (0 < H <= 20). Then H lines follow, each has three integers a, b, and c (0 <= a, b < N, 0 <= c < C) separated with whitespaces. This denotes that there is a high-way between city a and city b with color c.

There is a single blank line between test cases. A test case with 0 terminates the input, and this test case is not to be processed.


Output

For each test case, print a line with the minimum number of times Popo has to change tyres, so that he can achieve his goal. Otherwise print a line containing "No" only.


Sample Input

4 3 5
0 1 0
1 2 1
2 3 0
3 0 1
0 2 2

4 3 6
0 1 0
1 2 1
2 3 0
3 0 1
0 2 2
1 3 2

0 0 0


Sample Output

4
No

 


Author: SHI, Xiaohan
Source: Zhejiang University Local Contest 2004

Submit    Status

#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//int gcd(int a,int b){return b?gcd(b,a%b):a;}
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
#define MAX 1000000000
#define ms memset
#define maxn 100
using namespace std;
const int mod=1e9+7;
int n,c,m;
int x,y,z;///路和颜色
int d[20],cnt;///每个顶点的度数来判断是否有欧拉回路

/*
题目大意:给定n个顶点m条边的图,
每条边都有颜色,要求每次如果经历过不同颜色的路要换轮胎,
求最小的换轮胎次数。

首先什么情况下不可能?
图不是联通的情况下不可能,
或者是联通的但不是欧拉图。

下面的问题是如何存储边并以边为搜索对象?
把边用结构体存储起来,然后每一层都遍历结构体数组一遍。
*/

struct node
{
    int tx,ty;
    int cr;
    node(){}
};
node seq[maxn];
int vis[maxn];///标记边的数组

int pre[maxn];
int Find(int x)
{
    if(x == pre[x]) return x;
    return pre[x] = Find(pre[x]);
}
void Union(int x,int y)
{
    int fx=Find(x),fy=Find(y);
    if(fx==fy) return ;
    pre[fx]=fy;
}

void dfs(int pre,int lev,int t,int ans,int prec)///t为出发节点,lev为层数,pre为上一个的节点,ans存储的是目前换的轮胎次数,prec为上一个的颜色
{
   /// cout<<pre<<" "<<t<<endl;
    if(lev==m)
    {
        cnt=min(ans,cnt);
        return ;
    }
    for(int i=0;i<m;i++)
    {
        if(vis[i]) continue;
        if(seq[i].tx==t && seq[i].ty!=pre)
        {
            vis[i]=1;
            if(prec!=seq[i].cr)   dfs(t,lev+1,seq[i].ty,ans+1,seq[i].cr);
           else  dfs(t,lev+1,seq[i].ty,ans,seq[i].cr);
           vis[i]=0;
        }
        else if(seq[i].ty==t && seq[i].tx != pre)
        {
            vis[i]=1;
            if(prec!=seq[i].cr)  dfs(t,lev+1,seq[i].tx,ans+1,seq[i].cr);
           else  dfs(t,lev+1,seq[i].tx,ans,seq[i].cr);
           vis[i]=0;
        }
    }
}

int main()
{
    while( scanf("%d%d%d",&n,&c,&m)
          && ( n || c || m ) )
    {
        memset(d,0,sizeof(d));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++) pre[i]=i;

        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            x++,y++,z++; ///下标平移
            seq[i].tx=x , seq[i].ty=y , seq[i].cr=z;
            d[x]++,d[y]++;
            Union(x,y);
        }

        cnt=0;
        for( int i=1 ; i<=n ; i++)
            if(d[i]&1) cnt++;
        if( cnt!=2 && cnt!=0 ) { puts("No"); continue; }///判断是否存在欧拉回路

        cnt=0;
        for(int i=1;i<=n;i++)
             if(pre[i]==i) cnt++;
        if(cnt>1) { puts("No"); continue; }///判断图是否连通

        cnt=100000;///无穷大
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            dfs(-1,0,i,0,-1);
        }
        printf("%d\n",cnt-1);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值