DELL Software contest 2014 E题 1004 Suit Up

题目:

  • Time Limit: 4000/2000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others)
Description

Barney is going to stay in Farhampton for a week to prepare his wedding, so he decided to take along all his suits. We all know Barney wears his suit on any occasion. However, the trunk of his car doesn't have enough space for his dozens of ties after put in all his suits. You need help Barney to pick some from all the ties.

As we know, suits and ties are not randomly matched. But for each of Barney's suit, he always has a tie (or more) which is well matched with it. Your task is to pick the fewest ties so that whichever suit Barney puts on, he can find a matched tie from them.

Input

The input contains several test cases. The first line of each test case contains three integers T, S, M (1 ≤ T ≤ S ≤ 64, S ≤ M ≤ T+S). T is the number of ties and S is the number of suits. Then M lines follow, where there are two integers Ti (1 ≤ Ti ≤ T), Si (1 ≤ Si ≤ S) in each, which represents the Ti-th tie matches the Si-th suit. Note that there won't be duplicates among those M lines.

Output

For each test case, output the number of fewest ties Barney need to take along.

Sample Input

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

Sample Output

1
2


题意:

给出左边64个点,右边64个点,中间128条边,问左边最少选取多少个点可以覆盖完右边


解法:

搜索+神棍剪枝


思路:

对右边的点按边数升序排序,然后搜索

神棍剪枝:

”枚举没被覆盖的点,把对面所有跟这个没被覆盖的点有边的全选上,这些点全部算一个点“

7ms,加了个memcpy复制访问数组0ms

高效得不科学。。。据说比DLX还快。。。待考证

剪枝有待证明


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define inf 0x3f3f3f3f
struct node
{
	int to,next;
}edge[505];
struct node2
{
	int x,ps;//ps统计该点所连边数
}p[70];
int size,l[70],r[70];
int list[70][70];
int ans,n,m;
int vis[70];
int cmp(const void *a,const void *b)
{
	return (*(struct node2 *)a).ps>(*(struct node2 *)b).ps?1:-1;
}
void build(int x,int y)
{
	edge[size].to=y;
	edge[size].next=l[x];
	l[x]=size;
	size++;
	edge[size].to=x;
	edge[size].next=r[y];
	r[y]=size;
	size++;
	p[y].ps++;
}
void dfs(int now,int dep)
{
	int i,j,t,k,u;
	int less[70];
	int need;
	if(now==m+1)
	{
		if(dep<ans)
			ans=dep;
		return ;
	}
	for(i=r[p[now].x];i!=-1;i=edge[i].next)
	{
		//枚举取该点用哪一条边
		u=edge[i].to;
		for(j=l[u];j!=-1;j=edge[j].next)
			vis[edge[j].to]++;
		for(j=now+1;j<=m;j++)//找到第一个没访问过的点
			if(vis[p[j].x]==0)
				break;
		t=j;//记录下一个搜索点
		need=0;
		memcpy(less+1,vis+1,sizeof(int)*(m+1));
		//复制访问数组
		for(;j<=m;j++)
		{
			if(less[p[j].x])
				continue;
			need++;
			//记录至少还需要多少个点才能覆盖完
			less[p[j].x]=1;
			for(k=1;k<=list[p[j].x][0];k++)
				less[list[p[j].x][k]]=1;
		}
		if(dep+1+need>=ans);//无法更新
		else
			dfs(t,dep+1);
		for(j=l[u];j!=-1;j=edge[j].next)
			vis[edge[j].to]--;//回溯
	}
}
int main()
{
	int i,j,x,y,k,sum,u;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		//左边选取最少点覆盖完右边
		memset(l,-1,sizeof(l));
		memset(r,-1,sizeof(r));
		memset(p,0,sizeof(p));
		size=0;
		while(k--)
		{
			scanf("%d%d",&x,&y);
			build(x,y);
		}
		for(i=1;i<=m;i++)
		{
			p[i].x=i;
			memset(vis,0,sizeof(vis));
			//预处理剪枝中每一个点所覆盖的点,存入list
			vis[i]=1;
			sum=0;
			for(j=r[i];j!=-1;j=edge[j].next)
			{
				u=edge[j].to;
				for(k=l[u];k!=-1;k=edge[k].next)
				{
					if(vis[edge[k].to])
						continue;
					else
					{
						sum++;
						list[i][sum]=edge[k].to;
						vis[edge[k].to]=1;
					}
				}
			}
			list[i][0]=sum;
		}
		qsort(p+1,m,sizeof(p[0]),cmp);
		//按边数升序排序
		ans=inf;
		memset(vis,0,sizeof(vis));
		dfs(1,0);
		printf("%d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值