DD头子张京华
题目描述:(暂不提供)
这道题考场写费用流写挂了。然后最后输出了
−
1
-1
−1草草了事。
(
T
J
TJ
TJ上说输出
−
1
-1
−1零分,但是我却有30?
这道题是一道最小割。
这道题首先建两个
T
r
i
e
Trie
Trie,一个代表把每个编号按二进制顺序插入,另一个则是把它反着插进去。两点间连一条
I
N
F
INF
INF的边。然后对于相同的编号,两个
T
r
i
e
Trie
Trie上把最后的对应的(也就是相同编号在不同
T
r
i
e
Trie
Trie上的最后一个节点)点连一条
I
N
F
INF
INF的边。
然后对于每一种打钱方式,如果是前缀,就在顺序的 T r i e Trie Trie内将此前缀最后两位的边改为 D D DD DD值。
然后两个 T i r e Tire Tire的 r o o t root root分别为 S S S和 T T T。
建模就是这样了。考场费用流炸上天。(不过我觉得建模没错啊,就是 R R R了
既然建模都没了,这道题就是道最小割的板子了。
注意下连边,最好将所有边求好后在连。
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 3010;
const int INF = 0x3f3f3f3f;
inline int min(int a,int b) { return a < b ? a : b; }
ll ans;
char s[10],ch;
struct Edge{ int to,nxt,flow; } g[N << 1];
int last[N],cnt = 1;
int n,m,val[N][2],tag[10],dep[N]; //val代表Trie上的点连向它Trie上两个儿子的边的权值
int S,T,tot,son[N][2],l,r,q[N << 2];
void add(int u,int v,int w) { g[++cnt] = (Edge){ v,last[u],w }, last[u] = cnt; }
void Add_Edge(int u,int v,int w) { add(u,v,w), add(v,u,0); }
void insert(int x) //这里是在两颗Trie上插入编号
{
for(int i = 7;i >= 0; -- i) tag[i] = (1 << i) & x ? 1 : 0;
int x0 = S,x1 = T;
for(int i = 7;i >= 0; -- i)
{
if(!son[x0][tag[i]]) son[x0][tag[i]] = ++tot;
x0 = son[x0][tag[i]];
}
for(int i = 0;i <= 7; ++ i)
{
if(!son[x1][tag[i]]) son[x1][tag[i]] = ++tot;
x1 = son[x1][tag[i]];
}
Add_Edge(x0,x1,INF);
}
void link() //这里是将打钱方式的边加入
{
q[l = r = 1] = S;
for(;l <= r; ++ l)
{
if(son[q[l]][0]) Add_Edge(q[l],son[q[l]][0],val[q[l]][0]), q[++r] = son[q[l]][0];
if(son[q[l]][1]) Add_Edge(q[l],son[q[l]][1],val[q[l]][1]), q[++r] = son[q[l]][1];
}
q[l = r = 1] = T;
for(;l <= r; ++ l)
{
if(son[q[l]][0]) Add_Edge(son[q[l]][0],q[l],val[q[l]][0]), q[++r] = son[q[l]][0];
if(son[q[l]][1]) Add_Edge(son[q[l]][1],q[l],val[q[l]][1]), q[++r] = son[q[l]][1];
}
}
bool bfs()
{
memset(dep,0,sizeof dep);
dep[q[l = r = 1] = S] = 1;
for(;l <= r; ++ l)
for(int i = last[q[l]];i;i = g[i].nxt)
if(!dep[g[i].to] && g[i].flow) dep[q[++r] = g[i].to] = dep[q[l]] + 1;
return dep[T] > 0;
}
int dfs(int x,int flow)
{
if(x == T) return flow;
int now = 0;
for(int i = last[x];i;i = g[i].nxt)
if(dep[g[i].to] == dep[x] + 1 && g[i].flow)
{
int tmp = dfs(g[i].to,min(flow,g[i].flow));
g[i].flow -= tmp, g[i ^ 1].flow += tmp;
now += tmp, flow -= tmp;
if(flow == 0) return now;
}
if(now == 0) dep[x] = 0;
return now;
}
int main()
{
freopen("dd.in","r",stdin);
freopen("dd.out","w",stdout);
scanf("%d%d",&n,&m); S = ++tot, T = ++tot, memset(val,INF,sizeof val);
for(int i = 1,x;i <= n; ++ i) scanf("%d",&x), insert(x);
++m; for(int len,w;--m;)
{
ch = getchar(); while(ch != 'S' && ch != 'P') ch = getchar();
scanf(" %s %d",s,&w); len = strlen(s);
if(ch == 'P')
{
int x = S,fg = 1;
for(int i = 0;i < len - 1; ++ i)
{
if(!son[x][s[i] - '0']) { fg = 0; break; }
x = son[x][s[i] - '0'];
}
if(son[x][s[len - 1] - '0'] && fg) val[x][s[len - 1] - '0'] = min(val[x][s[len - 1] - '0'],w);
}
else
{
int x = T,fg = 1;
for(int i = len - 1;i; -- i)
{
if(!son[x][s[i] - '0']) { fg = 0; break; }
x = son[x][s[i] - '0'];
}
if(son[x][s[0] - '0'] && fg) val[x][s[0] - '0'] = min(val[x][s[0] - '0'],w);
}
}
link(), ans = 0;
while(bfs() && ans < INF) ans += dfs(S,INF);
printf("%lld\n",ans >= INF ? -1 : ans);
fclose(stdin); fclose(stdout);
return 0;
}
经过
G
S
M
GSM
GSM的辅导终于
A
A
A了。
代码写的很朴实,思路很清晰,所以也会比较长。
但是交上去后遭到
Z
J
J
ZJJ
ZJJ的嘲讽。
有兴趣的可以看看他的代码,比较简短。
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,l,r,ans,tot;
const int N = 1 << 10;
int q[N],st[N],dep[N],val[N]; char s[9];
struct EDGE{ int to,next,flow; } g[N << 5];
int min(int x,int y) { return x < y ? x : y; }
void add(int u,int v,int w)
{ g[++tot] = (EDGE){ v,st[u],w }, st[u] = tot; }
void add_edge(int u,int v,int w) { add(u,v,w), add(v,u,0); }
int BFS()
{
memset(dep,0,sizeof dep),
dep[q[l = r = 1] = 1] = 1;
for(;l <= r; ++ l)
for(int i = st[q[l]];i;i = g[i].next)
if(!dep[g[i].to] && g[i].flow)
dep[q[++r] = g[i].to] = dep[q[l]] + 1;
return dep[N - 1];
}
int dinic(int x,int flow)
{
int rest = 0;
if(x == N - 1) return flow;
for(int i = st[x],tmp;i;i = g[i].next)
if(dep[g[i].to] == dep[x] + 1 && g[i].flow)
{
tmp = dinic(g[i].to,min(g[i].flow,flow)), rest += tmp,
flow -= tmp, g[i].flow -= tmp, g[i ^ 1].flow += tmp;
if(!flow) return rest;
}
if(!rest) dep[x] = 0;
return rest;
}
int main()
{
freopen("dd.in","r",stdin),
freopen("dd.out","w",stdout);
memset(val,0x3f,sizeof val),
scanf("%d%d",&n,&m), tot = 1;
for(int i = 1,x,y,z;i <= n; ++ i)
{
scanf("%d",&x), y = z = 1;
for(int j = 8;j >= 1; -- j)
y = y * 2 + (x >> j - 1 & 1);
for(int j = 1;j <= 8; ++ j)
z = z * 2 + (x >> j - 1 & 1);
add_edge(y,N - z,0x3f3f3f3f);
}
for(int i = 1,x,y;i <= m; ++ i)
{
char c; scanf(" %c %s%d",&c,s + 1,&x);
if(c == 'P')
{
y = 1;
for(int j = 1,p = strlen(s + 1);j <= p; ++ j)
y = y * 2 + (s[j] ^ '0');
val[y] = min(val[y],x);
}
if(c == 'S')
{
y = 1;
for(int j = strlen(s + 1);j >= 1; -- j)
y = y * 2 + (s[j] ^ '0');
val[N - y] = min(val[N - y],x);
}
}
for(int i = 1;i <= 255; ++ i)
add_edge(N - (i << 1),N - i,val[N - (i << 1)]),
add_edge(N - (i << 1 | 1),N - i,val[N - (i << 1 | 1)]),
add_edge(i,i << 1,val[i << 1]), add_edge(i,i << 1 | 1,val[i << 1 | 1]);
for(ans = 0;ans < 0x3f3f3f3f && BFS();) ans += dinic(1,0x3f3f3f3f);
ans = min(ans,min(val[1],val[N - 1])),
printf("%d\n",ans >= 0x3f3f3f3f ? -1 : ans);
fclose(stdin), fclose(stdout);
return 0;
}
我表示别学他。