[题目]
[报告]
从题目中“每个CC只能涂某一个瓶子里的防晒霜”,可以大概猜到算法——二分图匹配。
的确,这道题是二分图匹配。图的左边是CC,右边是防晒霜。若某CC能用某防晒霜,那么就在这两者之间连线。当然,对于每个防晒霜,有必要而且是必须拆开——最后使所有防晒霜只能用1次——但这样会产生大量的防晒霜,这样显然不能在规定的空间内完成。所以必须处理。
第一种想法是:用防晒霜去匹配CC。因为每个CC都是唯一的,所以这个几乎可以直接套用经典的是匈牙利算法。不过这样的时间受不了——鄙人拿了70分。
在对第一种想法苦思冥想了3个小时,加了N多优化,仍然TLE,于是第二种想法应运而生:用CC去匹配防晒霜!——不过编程复杂度有点高……
同样以匈牙利算法为模板:枚举每一个CC,尝试着去匹配防晒霜。若没有现成的防晒霜(可以用的被别人用光了),那么就只能去和别人换。怎么换呢?枚举该CC可以用的所有的防晒霜,尝试着对这些防晒霜的主CC提出要求。那么被提出的CC就会按照匹配的方式去寻找,若他经过上面一番努力,仍无法获得,显然他是不会换的。那么就只能去找另一个。若所有的都不换,那么只能认为该CC悲剧了,就跳过它。
然后,90分——查数据后发现,那组数据的防晒霜的种类很少,防晒霜的总个数很多,而鄙人用的是HASH存储,不TLE才怪。怎么办呢?把HASH换成链表(或近似链表的东西)。
至此,该题目圆满AC……
[程序]
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#define N 2500
#define M 1000
#define nil NULL
using namespace std;
ifstream fin ("tanning.in");
ofstream fout ("tanning.out");
class link
{
public:
long dex;
link*next;
link(long dd=0,link*nn=nil)
{
dex=dd;next=nn;
}
}*t[M+1];
long n;
long ans,dx;
long a[N+1],b[N+1];
long s[M+1];
long f[N+1];
bool q[M+1];
long to[M+1];
static inline void join(long a,long b)
{
link*p=new link(b,t[a]);
t[a]=p;
}
static inline void calc() // 贪心初始解
{
for (long i=1;i<=n;i++)
for (long c=a[i];c<=b[i];c=to[c])
if (s[c])
{
f[i]=c;
link*p=new link(i,t[c]);
t[c]=p;
s[c]--;
ans++;
break;
}
}
static inline bool solve(long dex)
{
for (long c=a[dex];c<=b[dex];c=to[c]) // 扫描目前可以直接放入的空
if (s[c])
{
f[dex]=c;
link*p=new link(dex,t[c]);
t[c]=p;
s[c]--;
return true;
}
for (long c=a[dex];c<=b[dex];c=to[c])
if (!q[c])
{
q[c]=true;
for (link*p=t[c];p;p=p->next)
if (solve(p->dex))
{
f[dex]=c;
p->dex=dex;
return true;
}
}
return false;
}
int main(int argc, char *argv[])
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(to,0,sizeof(to));
fin >> n >> dx;
for (long i=1;i<=n;i++)
fin >> a[i] >> b[i];
memset(s,0,sizeof(s));
for (long c,ff;dx>0;dx--)
{
fin >> c >> ff;
s[c]+=ff;
}
for (long i=M;i>=0;i--)
t[i]=nil;
to[M]=M+1;
for (long i=M-1;i>=0;i--)
if (s[i+1]) to[i]=i+1;
else to[i]=to[i+1];
ans=0;
memset(f,0,sizeof(f));
calc();
for (long i=1;i<=n;i++)
if (!f[i]) // 未被匹配
{
memset(q,0,sizeof(q));
if (solve(i)) ans++;
}
fout << ans << endl;
return EXIT_SUCCESS;
}