按照做题顺序。
1、hdu2444
题意:
首先判断是否是二分图,如果不是的话输出No,如果是的话输出最大匹配。
题解:
按题意那么写。
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <set> #include <stack> #include <map> #include <ctime> #include <bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e10 using namespace std; struct edge{ int to,nxt; }e[4020030]; int n,m,cnt; int head[2005],link[2005]; bool vis[2005],col[2005]; void init(){ cnt=0; memset(head,-1,sizeof(head)); memset(col,0,sizeof(col)); } void add(int u,int v){ e[cnt].to=v, e[cnt].nxt=head[u],head[u]=cnt++; e[cnt].to=u, e[cnt].nxt=head[v],head[v]=cnt++; } bool judge(int u){ for (int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if (!col[v]){ col[v]=!col[u]; if (!judge(v)) return 0; } else if (col[v]==col[u]) return 0; } return 1; } bool dfs(int u){ for (int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if (!vis[v]){ vis[v]=1; if (link[v]==-1 || dfs(link[v])){ link[v]=u; return 1; } } } return 0; } int match(){ int ans=0; memset(link,-1,sizeof(link)); for (int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if (dfs(i)) ans++; } return ans; } int main(){ while (scanf("%d%d",&n,&m)!=EOF){ init(); for (int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); } col[1]=1; if (!judge(1)) puts("No"); else printf("%d\n",match()/2); } return 0; }
题意:
和上面那题一个意思,建图恶心点。
题解:
同上
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <set> #include <stack> #include <map> #include <ctime> #include <bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e10 using namespace std; struct edge{ int to,nxt; }e[10010]; int n,m,cnt; int head[110]; int col[110]; int mp[110][110]; void init(){ cnt=0; memset(head,-1,sizeof(head)); memset(col,-1,sizeof(col)); } void add(int u,int v){ e[cnt].to=v, e[cnt].nxt=head[u],head[u]=cnt++; e[cnt].to=u, e[cnt].nxt=head[v],head[v]=cnt++; } bool judge(int u,int clo){ col[u]=clo; for (int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if (col[v]!=-1){ if (col[v]==clo) return 0; continue; } if (!judge(v,!clo)) return 0; } return 1; } int main(){ while (scanf("%d",&n)==1){ memset(mp,0,sizeof(mp)); int x; for (int i=1;i<=n;i++){ while (scanf("%d",&x) && x) mp[i][x]=1; } init(); for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (mp[i][j]==0 || mp[j][i]==0){ add(i,j); } bool flag=1; for (int i=1;i<=n;i++){ if (col[i]==-1 && judge(i,0)==0){ flag=0; break; } } if (flag) puts("YES"); else puts("NO"); } return 0; }3、poj2594
题意:
最小路径覆盖。
题解:
二分图最小路径覆盖=顶点数-二分图最大匹配。
注意 此题中点可以重复经过,所以用floyd传递闭包维护一下连通性,给二分图上增加一些边。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e9 using namespace std; const int MAXN = 550; bool Map[MAXN][MAXN],Mask[MAXN]; int NX,NY; int cx[MAXN],cy[MAXN]; void Floyd(int N) //求传递闭包 { for(int k = 1; k <= N; ++k) { for(int i = 1; i <= N; ++i) { for(int j = 1; j <= N; ++j) { if(i != j && Map[i][k] && Map[k][j]) Map[i][j] = 1; } } } } int FindPath(int u) { for(int i = 1; i <= NY; ++i) { if(Map[u][i] && !Mask[i]) { Mask[i] = 1; if(cy[i] == -1 || FindPath(cy[i])) { cy[i] = u; cx[u] = i; return 1; } } } return 0; } int MaxMatch() //二分图最大匹配 { for(int i = 1; i <= NX; ++i) cx[i] = -1; for(int i = 1; i <= NY; ++i) cy[i] = -1; int res = 0; for(int i = 1; i <= NX; ++i) { if(cx[i] == -1) { for(int j = 1; j <= NY; ++j) Mask[j] = 0; res += FindPath(i); } } return res; } int main() { int N,M,u,v; while(~scanf("%d%d",&N,&M) && (N||M)) { memset(Map,0,sizeof(Map)); for(int i = 1; i <= M; ++i) { scanf("%d%d",&u,&v); Map[u][v] = 1; } Floyd(N); NX = NY = N; printf("%d\n",N - MaxMatch()); } return 0; }
题意:
能不能把一个每个字符都有权值的负环分割成两部分,当分割后的字符串是回文串时,权值为各字符之和,否则为1。求最大权值。
题解:
扩展KMP 或者 Manacher都可以 只要判断出以i点为中心,r为半径的字符串的权值,然后枚举一下,找到最大值。
代码:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; const int MAXN = 500010; int inde[30]; char str[MAXN]; char Ma[MAXN * 2]; int Mp[MAXN * 2]; int len; long long value[MAXN]; bool flaga[MAXN]; bool flagb[MAXN]; void Manacher(){ int l = 0; Ma[l ++] = '$'; Ma[l ++] = '#'; for(int i = 0; i < len; i ++){ Ma[l ++] = str[i]; Ma[l ++] = '#'; } Ma[l] = 0; int mx = 0, id = 0; for(int i = 0; i < l; i ++){ Mp[i] = mx > i ? min(Mp[2 * id - i], mx - i) : 1; while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i] ++; if(i + Mp[i] > mx){ mx = i + Mp[i]; id = i; } if(i - Mp[i] == 0) flaga[Mp[i] - 1] = true; if(i + Mp[i] == len + len + 2) flagb[Mp[i] - 1] = true; } } int T; int main(void){ cin >> T; while(T --){ for(int i = 0; i < 26; i ++){ cin >> inde[i]; } memset(flaga, false, sizeof(flaga)); memset(flagb, false, sizeof(flagb)); cin >> str; len = strlen(str); for(int i = 1; i <= len; i ++){ value[i] = value[i - 1] + inde[str[i - 1] - 'a']; } Manacher(); long long ans = 0; long long temp = 0; for(int i = 1; i < len; i ++){ if(flaga[i] == true) temp += value[i]; if(flagb[len - i] == true) temp += value[len] - value[i]; ans = ans > temp ? ans : temp; temp = 0; } cout << ans << endl; } }
题意:中文题。
题解:马拉车模板题。
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <set> #include <stack> #include <map> #include <ctime> #include <bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e10 using namespace std; const int N = 110009; char s[N], t[N<<1]; int p[N<<1]; int manacher(int len){ int id=1,mx=0; p[0]=1; for (int i=1;i<len;i++){ if (mx>i) p[i]=min(mx-i,p[2*id-i]); else p[i]=1; while (t[i+p[i]]==t[i-p[i]]) p[i]++; if (mx<p[i]+i){ mx=p[i]+i; id=i; } } int ans=p[1]; for (int i=1;i<len;i++){ if (ans<p[i]) ans=p[i]; } return ans-1; } int main(){ while (~scanf("%s",s)){ t[0]='@'; t[1]='#'; int len=strlen(s); for (int i=0;i<len;i++){ t[i*2+2]=s[i]; t[i*2+3]='#'; } printf("%d\n",manacher(len*2+2)); } return 0; }
题意:
要求字符串的一个子串 前1/3和中间1/3是回文,前1/3和后1/3相等。
题解:
由于回文串的性质,我们可以知道 前2/3和后2/3都是回文串,用manacher可以得到每个位置为起点的最长回文串一半的长度。然后从左往右扫一遍,看一下相对于当前位置的回文长度,找后面的位置是否满足要求。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e9 using namespace std; const int N = 100007; int num[N]; int tmp[N << 1]; int len[N << 1]; int n; int min( int x, int y ) { return x < y ? x : y; } void convert( int * st, int * dst ) { int l = 2 * n; dst[0] = -1; for ( int i = 1; i <= l; i += 2 ) { dst[i] = -2; dst[i + 1] = st[i / 2]; } dst[2 * n + 1] = -2; dst[2 * n + 2] = -3; } void manacher( int * st, int * dst ) { convert( st, dst ); int l = 2 * n + 1; int mx = 0, po = 0; for ( int i = 1; i <= l; i++ ) { if ( mx > i ) { len[i] = min( mx - i, len[2 * po - i] ); } else { len[i] = 1; } while ( dst[i - len[i]] == dst[i + len[i]] ) { len[i]++; } if ( len[i] + i > mx ) { mx = len[i] + i; po = i; } } } int main () { int t; scanf("%d", &t); for ( int _case = 1; _case <= t; _case++ ) { scanf("%d", &n); for ( int i = 0; i < n; i++ ) { scanf("%d", num + i); } manacher( num, tmp ); int ans = 0, l = 2 * n + 1; for ( int i = 1; i <= l; i += 2 ) { for ( int j = i + len[i] - 1; j - i > ans; j -= 2 ) { if ( j - i + 1 <= len[j] ) { ans = j - i; break; } } } ans = ans / 2 * 3; printf("Case #%d: %d\n", _case, ans); } return 0; }
8、
题意:
n个队员做m道题,第i个小时做第i个题目。Pij表示第i个队员能做出第j个题目的概率。
在任意时刻,任意两个队员的编程时间之差不允许超过1个小时。
问能做出最多题目的期望。
题解:
可以明显的看出,把n个队员作为一个集合,m个题做为一个集合。
因为题意里的第二句话,所以,我们做M/N次费用流求和。
带权二分图匹配。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e9 using namespace std; const int ME=1010; const int MV=100; struct edge{ int to,nxt,flow; db cost; }e[ME]; int head[MV],cnt; queue<int> q; int cur[MV],pre[MV]; bool used[MV],sign[MV]; int flow,n,m; db cost,dis[MV]; double p[16][1024]; bool spfa(int s,int t){ memset(used,0,sizeof(used)); memset(sign,0,sizeof(sign)); memset(dis,0,sizeof(dis)); used[s]=sign[s]=1; while (!q.empty()) q.pop(); q.push(s); while (!q.empty()){ int u=q.front(); q.pop(); used[u]=0; for (int i=head[u];~i;i=e[i].nxt){ if (e[i].flow<1) continue; int v=e[i].to; db c=e[i].cost; if (!sign[v] || dis[v]>dis[u]+c){ dis[v]=dis[u]+c; sign[v]=1; pre[v]=u; cur[v]=i; if (used[v]) continue; used[v]=1; q.push(v); } } } return sign[t]; } void init(){ cnt=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int flow,db cost){ e[cnt].to=v, e[cnt].flow=flow, e[cnt].cost=cost; e[cnt].nxt=head[u], head[u]=cnt++; e[cnt].to=u, e[cnt].flow=0, e[cnt].cost=-cost; e[cnt].nxt=head[v], head[v]=cnt++; } void solve(int s,int t){ flow=cost=0; while (spfa(s,t)){ int tmp=t; int now=inf; while (tmp!=s){ now=min(now,e[cur[tmp]].flow); tmp=pre[tmp]; } flow+=now; tmp=t; while (tmp!=s){ int id=cur[tmp]; cost+=now*e[id].cost; e[id].flow-=now; e[id^1].flow+=now; tmp=pre[tmp]; } } } db getcost(){ return cost; } int main(){ int tt,cas=1; scanf("%d",&tt); while (tt--){ scanf("%d%d",&n,&m); memset(p,0,sizeof(p)); for (int i=0;i<n;i++){ for (int j=0;j<m;j++){ scanf("%lf",&p[i][j]); } } printf("Case #%d: ",cas++); int part=m/n; if (m%n!=0) part++; db ans=0.0; for (int op=0;op<part;op++){ init(); int S=2*n+1; int T=2*n+2; int st=op*n; for (int i=0;i<n;i++) for (int j=0;j<n;j++) add(i,j+n,1,-p[i][j+st]); for (int i=0;i<n;i++) add(S,i,1,0); for (int i=0;i<n;i++) add(i+n,T,1,0); solve(S,T); ans-=getcost(); } printf("%.5f\n",ans); } return 0; }