HDU 3523 Image copy detection 最小带权匹配

昨天比赛,2010年多校第9场,貌似我们九个人中就我一个人研究了这题,也研究了一个多小时,而且刚开始对题意的理解用手算是过了样例,然后程序写出来时发现不对,手算的时候算错了,然后又读了题,然后觉得另一种题意应该是对的,在提交WA了几次之后我是终于彻彻底底明白题意了,但是比赛差不多结束了,而且受当时题意读错的影响,真明白的题意的时候思路扩展不开,就想到暴力的搜索了,然后就是预想中的TLE了!!!

貌似好多人都读不懂题:题中刚开始说有图,然后图的密度什么的,然后就是防止盗版,然后两个图的相似度是按照所有格子的距离和来算的,对于两个图中第i个格子的距离,即为第i个格子的数在整个图中n个格子的排名的绝对值差

然后题中图的每个格子的值为1~n,即代表的是格子在图中的排名的。

然后题中给了n和m,n代表一个图分的格数,有m个图,让你找一个图,使得这m个图到这个图的距离最小,并且这个图也必须满足给的图的性质,即每个格子的数的值是不同的(1~n).

解题思路:对于我们要找的目标图,它的每个格子可以取1~n的任意一个数,我们可以暴力求得第i个格子取1~n的任意一个值时m个图在这个格子的值,因为一个格子可以匹配1~n中的任意一个数,并且n个格子匹配的数都不同,于是很自然的想到了二分图最小带权匹配。。。

下面是代码:

/
// File Name: yes.cpp
// Author: wang
// mail: 
// Created Time: 2013-8-14 8:28:57
/
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <cmath>

#include <algorithm>
#include<iostream>
#include<queue>
#include <map>
using namespace std;
typedef long long ll;
#define INF (INT_MAX/10)
#define SQR(x) ((x)*(x))
#define rep(i, n) for (int i=0; i<(n); ++i)
#define repf(i, a, b) for (int i=(a); i<=(b); ++i)
#define repd(i, a, b) for (int i=(a); i>=(b); --i)
#define clr(ar,val) memset(ar, val, sizeof(ar))
#define inf 1000000000
#define N 205

class match{
public:
	int lx[N],ly[N];
	int Stack[N],next[N];
	bool visx[N],visy[N];
	int n;
	vector<int>vec[N];
	void init()
	{
		rep(i,n+1) vec[i].clear();
		memset(next,-1,sizeof(next));
	}
	bool bfs(int u)
	{
		visx[u]=true;
		rep(i,vec[u].size())
		{
			if(visy[i]==true) continue;
			if(lx[u]+ly[i]==vec[u][i])
			{
				visy[i]=true;
				if(next[i]==-1 || bfs(next[i]))
				{
					next[i]=u; return true;
				}
			}
			else 
				Stack[i]=min(Stack[i],lx[u]+ly[i]-vec[u][i]);
		}
		return false;
	}
	int km()
	{
		rep(i,n) lx[i]=-inf;
		rep(i,n)
		{
			ly[i]=0;
			rep(j,n) 
				lx[i]=max(lx[i],vec[i][j]);
		} 
		rep(i,n)
		{
			while(true)
			{
				memset(visx,false,sizeof(visx));
				memset(visy,false,sizeof(visy));
				rep(j,n) Stack[j]=inf;
				if(bfs(i)) break;
				int Min=inf;
				rep(j,n)
					if(visy[j]==false)
						Min=min(Min,Stack[j]);
				rep(j,n)
				{
					if(visx[j]==true) lx[j]-=Min;
					if(visy[j]==true) ly[j]+=Min;
				}
			}
		}
		int ans=0;
		rep(i,n)
			ans+=vec[next[i]][i];
		return ans;
	}
};
match sa;
int n,m;
int a[N][N];
void solve()
{
     scanf("%d%d",&n,&m);
	 rep(i,m)
		 rep(j,n) 
		 scanf("%d",&a[i][j]),--a[i][j];//转换为0~n-1的
	 sa.n=n;
	 sa.init();
     rep(i,n)
	 {
		 rep(j,n)//n个数的
		 {
			 int sum=0;
			 rep(k,m)
				 sum+=-abs(j-a[k][i]);
			 sa.vec[i].push_back(sum);//i与j匹配的
		 }
	 }
	 printf("%d\n",-sa.km());

}
int main()
{
      int test;
	  scanf("%d",&test);
	  repf(ror,1,test)
	  {
		  printf("Case #%d: ",ror);
		  solve();
	  }
	  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡定的小Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值