按照做题顺序。
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;
}
2、
题意:
和上面那题一个意思,建图恶心点。
题解:
同上
#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;
}
4、
题意:
能不能把一个每个字符都有权值的负环分割成两部分,当分割后的字符串是回文串时,权值为各字符之和,否则为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;
}
}
2、
题意:中文题。
题解:马拉车模板题。
代码:
#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;
}
3、
题意:
要求字符串的一个子串 前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;
}