[SCU3453] Stock Charts

题意:给出一个折线图,有N条线段,你想要把这些线段分成几个集合,使得每个集合中任意两条线段不相交

题解:

最小路径覆盖

把每条线段当成一个点,若两条线段不相交则连一条边,则问题可转化为用最少的路径数使所有点都被经过,即为最小路径覆盖

最小路径覆盖=N-二分图最大匹配

注意:连边只能往一个方向连,即表示出两点的连通性即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #define ll long long
 8 using namespace std;
 9 
10 const int N = 110;
11 
12 int T,n,m,ans,tot;
13 int a[N],b[N],dfn[N],s[N][30],g[N][N];
14 bool vis[N];
15 
16 int gi() {
17   int x=0,o=1; char ch=getchar();
18   while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
19   if(ch=='-') o=-1,ch=getchar();
20   while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
21   return o*x;
22 }
23 
24 void init() {
25   ans=0;
26   memset(s,0,sizeof(s));
27   memset(g,0,sizeof(g));
28   memset(a,-1,sizeof(a));
29   memset(b,-1,sizeof(b));
30 }
31 
32 bool cmp(const int &x, const int &y) {
33   return s[x][0]<s[y][0];
34 }
35 
36 bool check(int u, int v) {
37   for(int i=1; i<=m; i++) {
38     if(s[u][i]>=s[v][i]) return false;
39   }
40   return true;
41 }
42 
43 bool dfs(int u) {
44   for(int i=1; i<=n; i++) {
45     if(g[u][i] && !vis[i]) {
46       vis[i]=1;
47       if(dfs(b[i]) || b[i]==-1) {
48     b[i]=u,a[u]=i;
49     return true;
50       }
51     }
52   }
53   return false;
54 }
55 
56 int main() {
57   T=gi();
58   while(T--) {
59     init();
60     n=gi(),m=gi();
61     for(int i=1; i<=n; i++)
62       for(int j=1; j<=m; j++) {
63     s[i][j]=gi();
64     s[i][0]=max(s[i][0],s[i][j]);
65       }
66     for(int i=1; i<=n; i++) dfn[i]=i;
67     sort(dfn+1,dfn+n+1,cmp);
68     for(int i=1; i<=n; i++) {
69       int u=dfn[i],v;
70       for(int j=i+1; j<=n; j++) {
71     v=dfn[j];
72     if(check(u,v)) g[u][v]=1;
73       }
74     }
75     for(int i=1; i<=n; i++) {
76       if(a[i]==-1) {
77     memset(vis,0,sizeof(vis));
78     if(dfs(i)) ans++;
79       }
80     }
81     printf("Case #%d: %d
", ++tot,n-ans);
82   }
83   return 0;
84 }
原文地址:https://www.cnblogs.com/HLXZZ/p/7573523.html